From 0c8473f365d9e2e24b5a38d2ae6d1c85fe580db0 Mon Sep 17 00:00:00 2001
From: Brian Canini <canini.16@osu.edu>
Date: Wed, 14 Jul 2021 10:17:17 -0400
Subject: [PATCH] Upgrading drupal/core-recommended (9.2.0 => 9.2.1)

---
 composer.lock                                 |  26 +-
 vendor/composer/InstalledVersions.php         | 240 ++++++-------
 vendor/composer/installed.json                |  30 +-
 vendor/composer/installed.php                 | 240 ++++++-------
 web/core/MAINTAINERS.txt                      |   4 +-
 web/core/lib/Drupal.php                       |   2 +-
 .../Drupal/Component/Utility/UserAgent.php    |   2 +
 .../lib/Drupal/Core/Config/ConfigImporter.php |  10 +-
 .../lib/Drupal/Core/Database/Connection.php   |   8 +-
 .../lib/Drupal/Core/Database/Query/Select.php |   4 +-
 web/core/lib/Drupal/Core/DrupalKernel.php     |   2 +-
 .../Drupal/Core/Entity/ContentEntityBase.php  |   2 +-
 .../Drupal/Core/Entity/EntityFieldManager.php |  10 +-
 .../lib/Drupal/Core/Entity/EntityForm.php     |   2 +-
 .../Drupal/Core/Entity/EntityViewBuilder.php  |   2 +-
 .../Routing/DefaultHtmlRouteProvider.php      |   2 +-
 .../ActiveLinkResponseFilter.php              |   2 +-
 .../Drupal/Core/Extension/ModuleInstaller.php |   6 +-
 .../MimeType/ExtensionMimeTypeGuesser.php     |   6 +-
 web/core/lib/Drupal/Core/Form/FormState.php   |   4 +
 .../lib/Drupal/Core/Form/FormSubmitter.php    |   2 +-
 .../lib/Drupal/Core/Render/RenderCache.php    |  14 +-
 web/core/lib/Drupal/Core/Render/Renderer.php  |   2 +-
 .../Drupal/Core/StreamWrapper/LocalStream.php | 195 ++---------
 .../PhpStreamWrapperInterface.php             | 315 +++++++++++++++++-
 .../Core/Test/FunctionalTestSetupTrait.php    |   9 +-
 .../lib/Drupal/Core/Test/TestDiscovery.php    |   2 +-
 .../Core/Validation/DrupalTranslator.php      |   2 +-
 .../src/Plugin/migrate/source/Action.php      |   7 +-
 .../aggregator/processor/DefaultProcessor.php |   2 +-
 .../Plugin/migrate/source/AggregatorFeed.php  |   7 +-
 .../Plugin/migrate/source/AggregatorItem.php  |   7 +-
 .../Migrate/d7/MigrateAggregatorItemTest.php  |   2 +-
 .../AggregatorPluginSettingsBaseTest.php      |   6 +-
 .../Plugin/migrate/source/d7/BlockedIps.php   |   7 +-
 .../tests/src/Functional/BigPipeTest.php      |   2 +-
 .../FunctionalJavascript/BlockFilterTest.php  |   2 +-
 .../src/Kernel/NewDefaultThemeBlocksTest.php  |   2 +-
 .../book/src/Plugin/migrate/source/Book.php   |   7 +-
 .../book/tests/src/Functional/BookTest.php    |   6 +-
 .../BookJavascriptTest.php                    |   2 +-
 .../src/Plugin/CKEditorPlugin/Internal.php    |   4 +-
 .../src/Kernel/CKEditorPluginManagerTest.php  |  10 +-
 .../Plugin/CKEditorPlugin/LanguageTest.php    |   8 +-
 .../src/Plugin/migrate/source/d7/Color.php    |   5 +
 .../src/Plugin/migrate/source/CommentType.php |   7 +-
 .../src/Plugin/migrate/source/d6/Comment.php  |   5 +
 .../src/Plugin/migrate/source/d7/Comment.php  |   5 +
 .../source/d7/CommentEntityTranslation.php    |   7 +-
 .../src/Functional/CommentThreadingTest.php   |   8 +-
 .../Migrate/d6/MigrateCommentTypeTest.php     |   2 +-
 .../Migrate/d7/MigrateCommentTypeTest.php     |   2 +-
 .../src/Unit/CommentStatisticsUnitTest.php    |   2 +-
 .../tests/src/Unit/Entity/CommentLockTest.php |   4 +-
 .../Plugin/migrate/source/ContactCategory.php |   7 +-
 .../Plugin/migrate/source/ContactSettings.php |   7 +
 .../EntityStateChangeValidationTest.php       |   2 +-
 .../source/d7/EntityTranslationSettings.php   |   7 +-
 .../ContentTranslationUITestBase.php          |   4 +-
 ...ontentTranslationManageAccessCheckTest.php |  20 +-
 .../dblog/tests/src/Functional/DbLogTest.php  |   6 +-
 .../src/Functional/EditorSecurityTest.php     |  26 +-
 .../src/Unit/EditorXssFilter/StandardTest.php |   4 +-
 .../migrations/state/field.migrate_drupal.yml |   2 +
 .../process/d7/FieldOptionTranslation.php     |   1 +
 .../migrate/source/d7/FieldInstance.php       |   8 +-
 .../source/d7/FieldOptionTranslation.php      |   1 +
 .../src/Plugin/migrate/source/d7/ViewMode.php |   7 +-
 .../modules/field_test/field_test.module      |   4 +-
 .../EntityReferenceAutoCreateTest.php         |   8 +-
 .../tests/src/Functional/FieldTestBase.php    |   2 +-
 .../field/tests/src/Functional/FormTest.php   |   3 +-
 .../src/Functional/Views/FieldUITest.php      |   9 +-
 .../field/tests/src/Kernel/BulkDeleteTest.php |   2 +-
 ...rateFieldInstanceOptionTranslationTest.php |  86 +++++
 .../d7/MigrateFieldOptionTranslationTest.php  |  42 ++-
 .../Kernel/Migrate/d7/MigrateFieldTest.php    |   8 +-
 .../src/Unit/FieldConfigEntityUnitTest.php    |  40 +--
 .../ManageDisplayTest.php                     |   6 +-
 .../src/Functional/FileFieldWidgetTest.php    |   5 +-
 .../filter/src/Entity/FilterFormat.php        |   4 +-
 .../Plugin/migrate/source/d6/FilterFormat.php |   5 +
 .../Plugin/migrate/source/d7/FilterFormat.php |   5 +
 .../tests/src/Kernel/FilterKernelTest.php     |  86 ++---
 .../Migrate/d6/FilterFormatPermissionTest.php |   2 +-
 .../ForumListingBreadcrumbBuilderTest.php     |  10 +-
 .../ForumNodeBreadcrumbBuilderTest.php        |  10 +-
 .../hal/tests/src/Kernel/DenormalizeTest.php  |   2 +-
 .../help_topics/action.creating.html.twig     |  28 ++
 .../help_topics/action.overview.html.twig     |  25 ++
 .../help_topics/comment.configuring.html.twig |  43 +++
 .../comment.creating_type.html.twig           |  32 ++
 .../help_topics/comment.disabling.html.twig   |  28 ++
 .../help_topics/comment.moderating.html.twig  |  34 ++
 .../help_topics/comment.overview.html.twig    |  29 ++
 .../help_topics/core.quick_edit.html.twig     |  19 ++
 .../core.ui_accessibility.html.twig           |   4 +-
 .../help_topics/core.ui_components.html.twig  |  26 +-
 .../node.creating_content.html.twig           |  36 ++
 .../help_topics/node.creating_type.html.twig  |  36 ++
 .../help_topics/node.editing.html.twig        |  39 +++
 .../help_topics/node.overview.html.twig       |  19 ++
 .../help_topics/path.creating_alias.html.twig |  28 ++
 .../help_topics/path.editing_alias.html.twig  |  26 ++
 .../help_topics/path.overview.html.twig       |  24 ++
 .../taxonomy.configuring.html.twig            |  36 ++
 .../help_topics/taxonomy.overview.html.twig   |  24 ++
 .../help_topics/views.overview.html.twig      |   7 +-
 .../views_ui.bulk_operations.html.twig        |  30 ++
 .../src/Functional/HelpTopicSearchTest.php    |  22 ++
 .../tests/src/Unit/HelpTopicTwigTest.php      |   6 +-
 .../migrate/source/d6/ImageCachePreset.php    |   5 +
 .../Plugin/migrate/source/d7/ImageStyles.php  |   7 +-
 .../src/Functional/ImageFieldValidateTest.php |  10 +-
 .../image/tests/src/Kernel/ImageItemTest.php  |   2 +-
 .../Migrate/d7/MigrateImageStylesTest.php     |   2 +-
 .../image/tests/src/Unit/ImageStyleTest.php   |   2 +-
 .../tests/src/Unit/FormErrorHandlerTest.php   |  51 +--
 .../jsonapi/tests/src/Functional/NodeTest.php |   2 +-
 .../JsonApiDocumentTopLevelNormalizerTest.php |   6 +-
 .../tests/src/Kernel/Query/FilterTest.php     |  16 +-
 .../Functional/LanguageConfigurationTest.php  |   2 +-
 .../src/Unit/ConfigurableLanguageUnitTest.php |   4 +-
 .../layout_builder/layout_builder.module      |   1 +
 .../src/Functional/LayoutBuilderTest.php      |   1 +
 .../FunctionalJavascript/BlockFilterTest.php  |   3 +-
 .../BlockFormMessagesTest.php                 |   2 +-
 .../ContentPreviewToggleTest.php              |   2 +-
 .../FunctionalJavascript/InlineBlockTest.php  |   2 +-
 .../MoveBlockFormTest.php                     |   4 +-
 .../LayoutBuilderEntityViewDisplayTest.php    |   4 +-
 .../Plugin/Field/FieldWidget/LinkWidget.php   |  12 +-
 .../tests/src/Functional/LinkFieldTest.php    |  14 +
 .../Functional/LocaleImportFunctionalTest.php |   2 +-
 .../LocaleJavascriptTranslationTest.php       |   2 +-
 .../media/src/Form/EditorMediaDialog.php      |   2 +-
 .../src/Functional/ProviderRepositoryTest.php |   3 +-
 .../CKEditorIntegrationTest.php               |  27 ++
 .../media_library/media_library.module        |   4 +-
 .../src/MediaLibraryUiBuilder.php             |   2 +-
 .../MenuLinkContentAccessControlHandler.php   |   2 +-
 .../tests/src/Kernel/MenuLinksTest.php        |   4 +-
 .../Kernel/Migrate/d7/MigrateMenuLinkTest.php |   2 +-
 .../migrate/process/MigrationLookup.php       |  47 ++-
 .../src/Plugin/migrate/source/SqlBase.php     |   2 +-
 .../process/DownloadFunctionalTest.php        |   2 +-
 .../tests/src/Kernel/MigrateBundleTest.php    |  10 +-
 .../tests/src/Kernel/MigrateSkipRowTest.php   |   2 +-
 .../MigrateExecutableMemoryExceededTest.php   |  22 +-
 .../tests/src/Unit/MigrateExecutableTest.php  |   2 +-
 .../Unit/MigrateSqlIdMapEnsureTablesTest.php  | 113 +++----
 .../tests/src/Unit/MigrateSqlIdMapTest.php    |   4 +-
 .../tests/src/Unit/MigrateTestCase.php        |   2 +-
 .../tests/src/Unit/destination/ConfigTest.php |   4 +-
 .../src/Unit/process/MigrationLookupTest.php  |  33 ++
 .../tests/src/Unit/process/SubProcessTest.php |  27 +-
 .../state/migrate_drupal.migrate_drupal.yml   |   6 -
 .../src/Plugin/migrate/source/EmptySource.php |   6 +
 .../migrate/source/d7/FieldableEntity.php     |   5 +-
 .../migrate_drupal/tests/fixtures/drupal7.php | 246 +++++++++++++-
 .../tests/src/Kernel/StateFileExists.php      |   2 +-
 .../tests/src/Functional/d7/Upgrade7Test.php  |   4 +-
 .../migrations/state/node.migrate_drupal.yml  |   4 +
 web/core/modules/node/node.module             |   4 +-
 .../node/src/Plugin/Block/SyndicateBlock.php  |   3 +-
 .../src/Plugin/migrate/source/d6/Node.php     |   6 +-
 .../Plugin/migrate/source/d6/NodeComplete.php |   7 +-
 .../Plugin/migrate/source/d6/NodeRevision.php |   5 +
 .../src/Plugin/migrate/source/d6/NodeType.php |   5 +
 .../src/Plugin/migrate/source/d6/ViewMode.php |   7 +-
 .../src/Plugin/migrate/source/d7/Node.php     |   3 +-
 .../Plugin/migrate/source/d7/NodeComplete.php |   7 +-
 .../source/d7/NodeEntityTranslation.php       |   3 +-
 .../Plugin/migrate/source/d7/NodeRevision.php |   5 +
 .../src/Plugin/migrate/source/d7/NodeType.php |   5 +
 .../src/Functional/AssertButtonsTrait.php     |   4 +-
 .../src/Functional/NodeSyndicateBlockTest.php |   4 +
 .../Migrate/d6/MigrateNodeCompleteTest.php    |   7 +
 .../Migrate/d7/MigrateNodeCompleteTest.php    |  10 +
 .../Kernel/NodeAccessLanguageAwareTest.php    |  12 +-
 .../src/Kernel/NodeFieldOverridesTest.php     |   2 +-
 .../src/Plugin/migrate/source/d6/UrlAlias.php |   7 +-
 .../src/Plugin/migrate/source/d7/UrlAlias.php |   7 +-
 .../path_alias/tests/src/Kernel/AliasTest.php |   4 +-
 .../Plugin/migrate/source/d7/RdfMapping.php   |   5 +
 .../Unit/RdfMappingConfigEntityUnitTest.php   |  29 +-
 .../rest/tests/src/Unit/CollectRoutesTest.php |   2 +-
 .../Plugin/migrate/source/d6/SearchPage.php   |   8 +-
 .../Plugin/migrate/source/d7/SearchPage.php   |   8 +-
 .../tests/src/Kernel/SearchMatchTest.php      |   4 +-
 .../SerializedColumnNormalizerTrait.php       |  10 +-
 .../src/Kernel/EntitySerializationTest.php    |   4 +-
 .../Unit/Normalizer/EntityNormalizerTest.php  |  77 ++---
 .../SettingsTrayBlockFormTest.php             |   4 +-
 .../SettingsTrayTestBase.php                  |   4 +-
 .../src/Plugin/migrate/source/d7/Shortcut.php |   5 +
 .../Plugin/migrate/source/d7/ShortcutSet.php  |   5 +
 .../migrate/source/d7/ShortcutSetUsers.php    |   5 +
 .../src/Plugin/migrate/source/NodeCounter.php |   7 +-
 .../src/Plugin/migrate/source/Extension.php   |  23 +-
 .../system/src/Plugin/migrate/source/Menu.php |   7 +-
 .../migrate/source/d7/MenuTranslation.php     |   7 +-
 .../migrate/source/d7/ThemeSettings.php       |   8 +-
 .../modules/entity_test/entity_test.module    |   2 +-
 .../module_test/module_test.services.yml      |   7 +
 .../src/PluginManagerCacheClearer.php         |  47 +++
 .../src/Plugin/MockBlockManager.php           |   2 +-
 .../Functional/Form/ElementsLabelsTest.php    |   9 +-
 .../Render/HtmlResponseAttachmentsTest.php    |   7 +-
 .../src/Functional/Theme/ThemeUiTest.php      |   2 +-
 .../UpdatePathTestBaseFilledTest.php          |   2 +-
 ...ityReferenceSelectionReferenceableTest.php |   8 +-
 .../Kernel/Extension/ModuleHandlerTest.php    |   2 +-
 .../Kernel/Installer/UninstallKernelTest.php  |  21 ++
 .../src/Kernel/Scripts/DbCommandBaseTest.php  |   2 +
 .../src/Plugin/migrate/source/d6/Term.php     |   5 +-
 .../source/d6/TermLocalizedTranslation.php    |   5 +-
 .../src/Plugin/migrate/source/d6/TermNode.php |  24 +-
 .../migrate/source/d6/TermNodeRevision.php    |   8 +-
 .../Plugin/migrate/source/d6/Vocabulary.php   |   5 +
 .../migrate/source/d6/VocabularyPerType.php   |   7 +-
 .../source/d6/VocabularyTranslation.php       |   7 +-
 .../src/Plugin/migrate/source/d7/Term.php     |   5 +-
 .../source/d7/TermEntityTranslation.php       |   5 +-
 .../source/d7/TermLocalizedTranslation.php    |   5 +-
 .../migrate/source/d7/TermTranslation.php     |   5 +-
 .../Plugin/migrate/source/d7/Vocabulary.php   |   5 +
 .../source/d7/VocabularyTranslation.php       |   7 +-
 .../views/filter/TaxonomyIndexTidDepth.php    |   2 +-
 .../tour/tests/src/Functional/TourTest.php    |   2 +-
 .../Plugin/migrate/source/d7/TrackerNode.php  |   5 +
 .../Plugin/migrate/source/d7/TrackerUser.php  |   5 +
 .../Plugin/migrate/source/UpdateSettings.php  |   8 +-
 .../modules/update/src/UpdateProcessor.php    |   2 +-
 .../release-history/bbb_update_test.1_0.xml   |   2 +-
 .../release-history/ccc_update_test.1_0.xml   |   2 +-
 .../update_test_basetheme.1_1-sec.xml         |   4 +-
 .../update_test_subtheme.1_0.xml              |   2 +-
 .../src/Functional/UpdateContribTest.php      |   9 +-
 web/core/modules/user/src/AccountForm.php     |   6 +-
 .../src/Functional/RestRegisterUserTest.php   |   2 +-
 .../migrate/source/ProfileFieldTest.php       |   4 +-
 .../tests/src/Kernel/UserMailNotifyTest.php   |   2 +-
 .../tests/src/Kernel/UserRoleEntityTest.php   |   6 +-
 .../tests/src/Unit/PermissionHandlerTest.php  |  50 ++-
 .../views/src/Form/ViewsExposedForm.php       |   2 +-
 .../Plugin/views/cache/CachePluginBase.php    |   2 +-
 .../src/Plugin/views/field/EntityField.php    |   6 +-
 .../views/src/Plugin/views/join/Subquery.php  |   2 +-
 .../views/src/Plugin/views/query/Sql.php      |   2 +-
 web/core/modules/views/src/ViewExecutable.php |   2 +-
 ...views.view.test_distinct_click_sorting.yml | 263 +++++++++++++++
 .../tests/src/Functional/BulkFormTest.php     |   8 +-
 .../src/Functional/Handler/FieldWebTest.php   |  23 +-
 .../tests/src/Functional/Plugin/PagerTest.php |   4 +-
 .../Kernel/Entity/FilterEntityBundleTest.php  |   2 +-
 .../Entity/LatestRevisionFilterTest.php       |   2 +-
 .../src/Kernel/Handler/SortRandomTest.php     |   6 +-
 .../tests/src/Kernel/Handler/SortTest.php     |   8 +-
 .../tests/src/Unit/ViewExecutableTest.php     |   4 +-
 .../views/tests/src/Unit/ViewsDataTest.php    | 177 +++++-----
 web/core/modules/views/views.api.php          |   8 +-
 .../src/Functional/FilterNumericWebTest.php   |  11 +-
 .../demo_umami/themes/umami/css/base.css      |   1 +
 .../Template/ComposerProjectTemplatesTest.php |   2 +-
 .../FunctionalTests/BrowserTestBaseTest.php   |  13 +
 ...erInputMappingOnFieldDeltaElementsTest.php |   4 +-
 .../InstallerNonDefaultDatabaseDriverTest.php |   6 +-
 .../Installer/InstallerTest.php               |   6 +-
 .../Update/UpdatePathTestBase.php             |   2 +-
 .../Update/UpdatePathTestBaseTest.php         |   2 +-
 .../Core/Action/EmailActionTest.php           |   4 +-
 .../Core/Config/ExportStorageManagerTest.php  |   8 +-
 .../Config/ImportStorageTransformerTest.php   |  10 +-
 .../Core/Database/SelectSubqueryTest.php      |   8 +
 .../Entity/EntityDefinitionUpdateTest.php     |   4 +-
 .../Core/Entity/EntityDuplicateTest.php       |   2 +-
 .../EntityHasFieldConstraintValidatorTest.php |   2 +-
 .../Entity/EntityRevisionTranslationTest.php  |   4 +-
 .../Core/Installer/InstallerLanguageTest.php  |   2 +-
 .../Core/Menu/MenuTreeStorageTest.php         |   2 +-
 .../Core/Routing/RouteProviderTest.php        |   3 +-
 .../Drupal/KernelTests/KernelTestBase.php     |   2 +-
 .../Annotation/Doctrine/DocParserTest.php     |  20 +-
 .../DependencyInjection/ContainerTest.php     |  10 +-
 .../Component/Diff/Engine/DiffEngineTest.php  |   2 +-
 .../Component/Discovery/YamlDiscoveryTest.php |   2 +-
 .../Tests/Component/Graph/GraphTest.php       |   2 +
 .../Tests/Component/Utility/XssTest.php       |   4 +-
 .../Tests/Core/Access/AccessManagerTest.php   |  27 +-
 .../Core/Access/CustomAccessCheckTest.php     |  36 +-
 .../Tests/Core/Ajax/AjaxResponseTest.php      |   2 +-
 .../Asset/LibraryDiscoveryCollectorTest.php   |  44 +--
 .../Tests/Core/Cache/CacheCollectorTest.php   |  51 ++-
 .../Cache/Context/SessionCacheContextTest.php |   8 +-
 .../Entity/ConfigEntityBaseUnitTest.php       |  15 +-
 .../Entity/EntityDisplayModeBaseUnitTest.php  |  12 +-
 .../Driver/pgsql/PostgresqlSchemaTest.php     |  16 +-
 .../Core/Database/EmptyStatementTest.php      |   2 +-
 .../Tests/Core/Database/OrderByTest.php       |   2 +-
 .../Drupal/Tests/Core/Datetime/DateTest.php   |  28 +-
 .../Core/Entity/ContentEntityBaseUnitTest.php |  47 +--
 .../Enhancer/EntityRouteEnhancerTest.php      |  10 +-
 .../Tests/Core/Entity/EntityUnitTest.php      |  60 ++--
 .../Tests/Core/Entity/EntityUrlTest.php       |   4 +-
 .../KeyValueEntityStorageTest.php             | 125 ++-----
 .../Sql/SqlContentEntityStorageSchemaTest.php |  10 +-
 .../Core/Extension/InfoParserUnitTest.php     |   8 +-
 .../Core/Extension/ModuleHandlerTest.php      |  20 +-
 .../Tests/Core/Extension/ThemeHandlerTest.php |   4 +-
 .../Drupal/Tests/Core/Form/FormCacheTest.php  |  10 +-
 .../Tests/Core/Form/FormErrorHandlerTest.php  |  26 +-
 .../Tests/Core/Logger/LoggerChannelTest.php   |   2 +-
 .../Core/Menu/ContextualLinkManagerTest.php   |   7 +-
 .../DefaultMenuLinkTreeManipulatorsTest.php   |  23 +-
 .../Tests/Core/Menu/LocalTaskManagerTest.php  |  27 +-
 .../Core/Menu/StaticMenuLinkOverridesTest.php |  55 ++-
 .../Core/PageCache/NoSessionOpenTest.php      |  13 +-
 .../DerivativeDiscoveryDecoratorTest.php      |  16 +-
 .../Plugin/Discovery/HookDiscoveryTest.php    |  36 +-
 .../Drupal/Tests/Core/Render/RendererTest.php |  50 ++-
 .../Routing/ContentTypeHeaderMatcherTest.php  |   2 +-
 .../Routing/RequestFormatRouteFilterTest.php  |   2 +-
 .../Tests/Core/Routing/RouteBuilderTest.php   |  37 +-
 .../Tests/Core/Routing/RouteCompilerTest.php  |   8 +-
 .../Tests/Core/Routing/UrlGeneratorTest.php   |   2 +-
 .../Session/WriteSafeSessionHandlerTest.php   |  18 +-
 .../Core/TempStore/PrivateTempStoreTest.php   |  71 ++--
 .../Core/TempStore/SharedTempStoreTest.php    |  87 +++--
 .../Tests/Core/Template/TwigSandboxTest.php   |  12 +-
 .../Tests/Core/Test/JUnitConverterTest.php    |   8 +-
 .../Tests/Core/Theme/ThemeNegotiatorTest.php  |  13 +-
 web/core/tests/Drupal/Tests/Core/UrlTest.php  |  30 +-
 .../Tests/Core/Utility/LinkGeneratorTest.php  |   6 +-
 .../tests/Drupal/Tests/DocumentElement.php    |  84 +++++
 web/core/tests/bootstrap.php                  |   1 +
 web/core/themes/olivero/css/base/base.css     |   4 +-
 .../themes/olivero/css/base/base.pcss.css     |   4 +-
 .../olivero/css/base/variables.pcss.css       |   2 +
 .../themes/olivero/css/components/button.css  |   5 -
 .../olivero/css/components/button.pcss.css    |   7 -
 .../olivero/css/components/comments.css       |   8 -
 .../olivero/css/components/comments.pcss.css  |   4 -
 .../olivero/css/components/field-image.css    | 152 ---------
 .../css/components/field-image.pcss.css       |  62 ----
 .../themes/olivero/css/components/footer.css  |   2 -
 .../olivero/css/components/footer.pcss.css    |   4 +-
 .../css/components/header-sticky-toggle.css   |   4 +-
 .../components/header-sticky-toggle.pcss.css  |   4 +-
 .../olivero/css/components/messages.css       |   3 +-
 .../olivero/css/components/messages.pcss.css  |   3 +-
 .../components/navigation/menu-sidebar.css    |  86 +++++
 .../menu-sidebar.pcss.css}                    |   8 +-
 .../navigation/nav-primary-button.css         |   2 +-
 .../navigation/nav-primary-button.pcss.css    |   2 +-
 .../navigation/nav-primary-wide.css           |   6 +-
 .../navigation/nav-primary-wide.pcss.css      |   6 +-
 .../css/components/navigation/nav-primary.css |   4 +-
 .../navigation/nav-primary.pcss.css           |   3 +-
 .../components/navigation/wide-nav-expand.css |   4 +-
 .../navigation/wide-nav-expand.pcss.css       |   4 +-
 .../themes/olivero/css/components/sidebar.css |  82 -----
 .../olivero/css/components/site-header.css    |  12 +-
 .../css/components/site-header.pcss.css       |  12 +-
 .../themes/olivero/css/components/tabs.css    |   1 +
 .../olivero/css/components/tabs.pcss.css      |   1 +
 .../themes/olivero/css/components/tags.css    |   9 +-
 .../olivero/css/components/tags.pcss.css      |   6 +-
 .../olivero/css/components/wide-image.css     | 146 ++++++++
 .../css/components/wide-image.pcss.css        |  60 ++++
 web/core/themes/olivero/css/layout/grid.css   |   8 +-
 .../themes/olivero/css/layout/grid.pcss.css   |   4 +
 .../css/layout/layout-content-narrow.css      |  16 +
 .../css/layout/layout-content-narrow.pcss.css |  17 +
 .../olivero/css/layout/layout-sidebar.css     | 126 +++----
 .../css/layout/layout-sidebar.pcss.css        |  57 +---
 .../themes/olivero/css/layout/social-bar.css  |   6 +-
 .../olivero/css/layout/social-bar.pcss.css    |   2 +-
 web/core/themes/olivero/js/checkbox.es6.js    |   2 +-
 web/core/themes/olivero/js/comments.es6.js    |  82 +++--
 web/core/themes/olivero/js/comments.js        |  51 +--
 web/core/themes/olivero/js/messages.es6.js    |  11 +-
 web/core/themes/olivero/js/navigation.es6.js  |  53 +--
 web/core/themes/olivero/js/navigation.js      |  22 +-
 web/core/themes/olivero/js/scripts.es6.js     |  47 ++-
 web/core/themes/olivero/js/scripts.js         |   4 +-
 web/core/themes/olivero/js/search.es6.js      |  20 ++
 .../olivero/js/second-level-navigation.es6.js |  56 ++--
 .../olivero/js/second-level-navigation.js     |  26 +-
 web/core/themes/olivero/js/tabs.es6.js        |  31 ++
 web/core/themes/olivero/olivero.libraries.yml |   9 +-
 web/core/themes/olivero/olivero.theme         |  47 ++-
 .../templates/content/comment.html.twig       |   3 +-
 .../templates/field/field--comment.html.twig  |   2 +-
 .../olivero/templates/layout/page.html.twig   |  21 +-
 .../layout/region--content-below.html.twig    |   4 +-
 .../layout/region--content.html.twig          |   2 +-
 .../templates/layout/region--social.html.twig |   4 +-
 .../navigation/menu--primary-menu.html.twig   |  26 +-
 399 files changed, 4441 insertions(+), 2594 deletions(-)
 create mode 100644 web/core/modules/field/tests/src/Kernel/Migrate/d7/MigrateFieldInstanceOptionTranslationTest.php
 create mode 100644 web/core/modules/help_topics/help_topics/action.creating.html.twig
 create mode 100644 web/core/modules/help_topics/help_topics/action.overview.html.twig
 create mode 100644 web/core/modules/help_topics/help_topics/comment.configuring.html.twig
 create mode 100644 web/core/modules/help_topics/help_topics/comment.creating_type.html.twig
 create mode 100644 web/core/modules/help_topics/help_topics/comment.disabling.html.twig
 create mode 100644 web/core/modules/help_topics/help_topics/comment.moderating.html.twig
 create mode 100644 web/core/modules/help_topics/help_topics/comment.overview.html.twig
 create mode 100644 web/core/modules/help_topics/help_topics/core.quick_edit.html.twig
 create mode 100644 web/core/modules/help_topics/help_topics/node.creating_content.html.twig
 create mode 100644 web/core/modules/help_topics/help_topics/node.creating_type.html.twig
 create mode 100644 web/core/modules/help_topics/help_topics/node.editing.html.twig
 create mode 100644 web/core/modules/help_topics/help_topics/node.overview.html.twig
 create mode 100644 web/core/modules/help_topics/help_topics/path.creating_alias.html.twig
 create mode 100644 web/core/modules/help_topics/help_topics/path.editing_alias.html.twig
 create mode 100644 web/core/modules/help_topics/help_topics/path.overview.html.twig
 create mode 100644 web/core/modules/help_topics/help_topics/taxonomy.configuring.html.twig
 create mode 100644 web/core/modules/help_topics/help_topics/taxonomy.overview.html.twig
 create mode 100644 web/core/modules/help_topics/help_topics/views_ui.bulk_operations.html.twig
 create mode 100644 web/core/modules/system/tests/modules/module_test/module_test.services.yml
 create mode 100644 web/core/modules/system/tests/modules/module_test/src/PluginManagerCacheClearer.php
 create mode 100644 web/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_distinct_click_sorting.yml
 create mode 100644 web/core/tests/Drupal/Tests/DocumentElement.php
 delete mode 100644 web/core/themes/olivero/css/components/field-image.css
 delete mode 100644 web/core/themes/olivero/css/components/field-image.pcss.css
 create mode 100644 web/core/themes/olivero/css/components/navigation/menu-sidebar.css
 rename web/core/themes/olivero/css/components/{sidebar.pcss.css => navigation/menu-sidebar.pcss.css} (88%)
 delete mode 100644 web/core/themes/olivero/css/components/sidebar.css
 create mode 100644 web/core/themes/olivero/css/components/wide-image.css
 create mode 100644 web/core/themes/olivero/css/components/wide-image.pcss.css

diff --git a/composer.lock b/composer.lock
index 6dd2e6af66..583da1741a 100644
--- a/composer.lock
+++ b/composer.lock
@@ -2955,16 +2955,16 @@
         },
         {
             "name": "drupal/core",
-            "version": "9.2.0",
+            "version": "9.2.1",
             "source": {
                 "type": "git",
                 "url": "https://github.com/drupal/core.git",
-                "reference": "0231ec3b5a195d39ab02680672736de781a59599"
+                "reference": "20eb99aa59a265d22a21a4d6fde70901c3b5a37c"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/drupal/core/zipball/0231ec3b5a195d39ab02680672736de781a59599",
-                "reference": "0231ec3b5a195d39ab02680672736de781a59599",
+                "url": "https://api.github.com/repos/drupal/core/zipball/20eb99aa59a265d22a21a4d6fde70901c3b5a37c",
+                "reference": "20eb99aa59a265d22a21a4d6fde70901c3b5a37c",
                 "shasum": ""
             },
             "require": {
@@ -3203,9 +3203,9 @@
             ],
             "description": "Drupal is an open source content management platform powering millions of websites and applications.",
             "support": {
-                "source": "https://github.com/drupal/core/tree/9.2.0"
+                "source": "https://github.com/drupal/core/tree/9.2.1"
             },
-            "time": "2021-06-16T12:31:16+00:00"
+            "time": "2021-07-07T13:04:41+00:00"
         },
         {
             "name": "drupal/core-composer-scaffold",
@@ -3259,16 +3259,16 @@
         },
         {
             "name": "drupal/core-recommended",
-            "version": "9.2.0",
+            "version": "9.2.1",
             "source": {
                 "type": "git",
                 "url": "https://github.com/drupal/core-recommended.git",
-                "reference": "436c459d1c9c8966b4d01e239da1b9165e91aa9d"
+                "reference": "f043a94e9a8aa60016974d60648508258a51bf86"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/drupal/core-recommended/zipball/436c459d1c9c8966b4d01e239da1b9165e91aa9d",
-                "reference": "436c459d1c9c8966b4d01e239da1b9165e91aa9d",
+                "url": "https://api.github.com/repos/drupal/core-recommended/zipball/f043a94e9a8aa60016974d60648508258a51bf86",
+                "reference": "f043a94e9a8aa60016974d60648508258a51bf86",
                 "shasum": ""
             },
             "require": {
@@ -3277,7 +3277,7 @@
                 "doctrine/annotations": "1.13.1",
                 "doctrine/lexer": "1.2.1",
                 "doctrine/reflection": "1.2.2",
-                "drupal/core": "9.2.0",
+                "drupal/core": "9.2.1",
                 "egulias/email-validator": "2.1.25",
                 "guzzlehttp/guzzle": "6.5.5",
                 "guzzlehttp/promises": "1.4.1",
@@ -3340,9 +3340,9 @@
             ],
             "description": "Locked core dependencies; require this project INSTEAD OF drupal/core.",
             "support": {
-                "source": "https://github.com/drupal/core-recommended/tree/9.2.0"
+                "source": "https://github.com/drupal/core-recommended/tree/9.2.1"
             },
-            "time": "2021-06-16T12:31:16+00:00"
+            "time": "2021-07-07T13:04:41+00:00"
         },
         {
             "name": "drupal/crop",
diff --git a/vendor/composer/InstalledVersions.php b/vendor/composer/InstalledVersions.php
index 0534046ac7..79490ff8be 100644
--- a/vendor/composer/InstalledVersions.php
+++ b/vendor/composer/InstalledVersions.php
@@ -30,7 +30,7 @@ class InstalledVersions
     'aliases' => 
     array (
     ),
-    'reference' => 'a89ed315c5f4d36ea9513b4dfeef27d25a4975ea',
+    'reference' => '481e21ac36751a525f541979c65002ec3bb47e05',
     'name' => 'osu-asc-webservices/d8-upstream',
   ),
   'versions' => 
@@ -298,7 +298,7 @@ class InstalledVersions
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/addtocalendar' => 
@@ -332,7 +332,7 @@ class InstalledVersions
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/allowed_formats' => 
@@ -357,28 +357,28 @@ class InstalledVersions
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/ban' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/bartik' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/basic_auth' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/better_exposed_filters' => 
@@ -394,21 +394,21 @@ class InstalledVersions
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/block' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/block_content' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/block_field' => 
@@ -442,7 +442,7 @@ class InstalledVersions
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/bootstrap' => 
@@ -458,7 +458,7 @@ class InstalledVersions
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/cache_control_override' => 
@@ -483,7 +483,7 @@ class InstalledVersions
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/ckeditor_indentblock' => 
@@ -499,35 +499,35 @@ class InstalledVersions
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/classy' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/color' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/comment' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/config' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/config_direct_save' => 
@@ -561,7 +561,7 @@ class InstalledVersions
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/config_update' => 
@@ -613,7 +613,7 @@ class InstalledVersions
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/content_access' => 
@@ -629,58 +629,58 @@ class InstalledVersions
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/content_translation' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/contextual' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/core' => 
     array (
-      'pretty_version' => '9.2.0',
-      'version' => '9.2.0.0',
+      'pretty_version' => '9.2.1',
+      'version' => '9.2.1.0',
       'aliases' => 
       array (
       ),
-      'reference' => '0231ec3b5a195d39ab02680672736de781a59599',
+      'reference' => '20eb99aa59a265d22a21a4d6fde70901c3b5a37c',
     ),
     'drupal/core-annotation' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/core-assertion' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/core-bridge' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/core-class-finder' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/core-composer-scaffold' => 
@@ -696,156 +696,156 @@ class InstalledVersions
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/core-dependency-injection' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/core-diff' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/core-discovery' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/core-event-dispatcher' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/core-file-cache' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/core-file-security' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/core-filesystem' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/core-front-matter' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/core-gettext' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/core-graph' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/core-http-foundation' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/core-php-storage' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/core-plugin' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/core-proxy-builder' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/core-recommended' => 
     array (
-      'pretty_version' => '9.2.0',
-      'version' => '9.2.0.0',
+      'pretty_version' => '9.2.1',
+      'version' => '9.2.1.0',
       'aliases' => 
       array (
       ),
-      'reference' => '436c459d1c9c8966b4d01e239da1b9165e91aa9d',
+      'reference' => 'f043a94e9a8aa60016974d60648508258a51bf86',
     ),
     'drupal/core-render' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/core-serialization' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/core-transliteration' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/core-utility' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/core-uuid' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/core-version' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/crop' => 
@@ -870,21 +870,21 @@ class InstalledVersions
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/datetime_range' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/dblog' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/dropzonejs' => 
@@ -909,14 +909,14 @@ class InstalledVersions
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/editor' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/editor_advanced_link' => 
@@ -986,7 +986,7 @@ class InstalledVersions
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/entity_reference_revisions' => 
@@ -1011,7 +1011,7 @@ class InstalledVersions
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/field_group' => 
@@ -1027,7 +1027,7 @@ class InstalledVersions
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/field_permissions' => 
@@ -1043,14 +1043,14 @@ class InstalledVersions
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/file' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/file_browser' => 
@@ -1066,7 +1066,7 @@ class InstalledVersions
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/focal_point' => 
@@ -1082,7 +1082,7 @@ class InstalledVersions
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/google_analytics' => 
@@ -1107,28 +1107,28 @@ class InstalledVersions
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/help' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/help_topics' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/history' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/honeypot' => 
@@ -1144,7 +1144,7 @@ class InstalledVersions
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/inline_entity_form' => 
@@ -1160,7 +1160,7 @@ class InstalledVersions
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/jquery_ui' => 
@@ -1203,28 +1203,28 @@ class InstalledVersions
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/language' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/layout_builder' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/layout_discovery' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/libraries' => 
@@ -1240,7 +1240,7 @@ class InstalledVersions
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/link_attributes' => 
@@ -1265,7 +1265,7 @@ class InstalledVersions
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/mathjax' => 
@@ -1281,7 +1281,7 @@ class InstalledVersions
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/media_entity_browser' => 
@@ -1306,7 +1306,7 @@ class InstalledVersions
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/menu_block' => 
@@ -1340,14 +1340,14 @@ class InstalledVersions
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/menu_ui' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/metatag' => 
@@ -1363,7 +1363,7 @@ class InstalledVersions
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/migrate_devel' => 
@@ -1379,21 +1379,21 @@ class InstalledVersions
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/migrate_drupal_multilingual' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/migrate_drupal_ui' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/migrate_plus' => 
@@ -1418,7 +1418,7 @@ class InstalledVersions
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/mobile_detect' => 
@@ -1461,28 +1461,28 @@ class InstalledVersions
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/olivero' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/options' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/page_cache' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/pantheon_advanced_page_cache' => 
@@ -1507,14 +1507,14 @@ class InstalledVersions
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/path_alias' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/pathauto' => 
@@ -1530,14 +1530,14 @@ class InstalledVersions
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/rdf' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/rebuild_cache_access' => 
@@ -1580,14 +1580,14 @@ class InstalledVersions
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/rest' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/roleassign' => 
@@ -1612,7 +1612,7 @@ class InstalledVersions
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/search_api' => 
@@ -1637,28 +1637,28 @@ class InstalledVersions
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/settings_tray' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/seven' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/shortcut' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/simple_gmap' => 
@@ -1728,21 +1728,21 @@ class InstalledVersions
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/stark' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/statistics' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/superfish' => 
@@ -1767,35 +1767,35 @@ class InstalledVersions
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/system' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/taxonomy' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/telephone' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/text' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/token' => 
@@ -1811,21 +1811,21 @@ class InstalledVersions
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/tour' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/tracker' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/twig_tweak' => 
@@ -1850,14 +1850,14 @@ class InstalledVersions
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/user' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/userprotect' => 
@@ -1891,7 +1891,7 @@ class InstalledVersions
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/views_ajax_history' => 
@@ -1952,7 +1952,7 @@ class InstalledVersions
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/webform' => 
@@ -1968,14 +1968,14 @@ class InstalledVersions
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/workspaces' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drush-ops/behat-drush-endpoint' => 
@@ -2226,7 +2226,7 @@ class InstalledVersions
       'aliases' => 
       array (
       ),
-      'reference' => 'a89ed315c5f4d36ea9513b4dfeef27d25a4975ea',
+      'reference' => '481e21ac36751a525f541979c65002ec3bb47e05',
     ),
     'pantheon-systems/quicksilver-pushback' => 
     array (
diff --git a/vendor/composer/installed.json b/vendor/composer/installed.json
index 9855477e4a..864a6a343e 100644
--- a/vendor/composer/installed.json
+++ b/vendor/composer/installed.json
@@ -3032,17 +3032,17 @@
         },
         {
             "name": "drupal/core",
-            "version": "9.2.0",
-            "version_normalized": "9.2.0.0",
+            "version": "9.2.1",
+            "version_normalized": "9.2.1.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/drupal/core.git",
-                "reference": "0231ec3b5a195d39ab02680672736de781a59599"
+                "reference": "20eb99aa59a265d22a21a4d6fde70901c3b5a37c"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/drupal/core/zipball/0231ec3b5a195d39ab02680672736de781a59599",
-                "reference": "0231ec3b5a195d39ab02680672736de781a59599",
+                "url": "https://api.github.com/repos/drupal/core/zipball/20eb99aa59a265d22a21a4d6fde70901c3b5a37c",
+                "reference": "20eb99aa59a265d22a21a4d6fde70901c3b5a37c",
                 "shasum": ""
             },
             "require": {
@@ -3207,7 +3207,7 @@
                 "drupal/workflows": "self.version",
                 "drupal/workspaces": "self.version"
             },
-            "time": "2021-06-16T12:31:16+00:00",
+            "time": "2021-07-07T13:04:41+00:00",
             "type": "drupal-core",
             "extra": {
                 "drupal-scaffold": {
@@ -3287,7 +3287,7 @@
             ],
             "description": "Drupal is an open source content management platform powering millions of websites and applications.",
             "support": {
-                "source": "https://github.com/drupal/core/tree/9.2.0"
+                "source": "https://github.com/drupal/core/tree/9.2.1"
             },
             "install-path": "../../web/core"
         },
@@ -3343,17 +3343,17 @@
         },
         {
             "name": "drupal/core-recommended",
-            "version": "9.2.0",
-            "version_normalized": "9.2.0.0",
+            "version": "9.2.1",
+            "version_normalized": "9.2.1.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/drupal/core-recommended.git",
-                "reference": "436c459d1c9c8966b4d01e239da1b9165e91aa9d"
+                "reference": "f043a94e9a8aa60016974d60648508258a51bf86"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/drupal/core-recommended/zipball/436c459d1c9c8966b4d01e239da1b9165e91aa9d",
-                "reference": "436c459d1c9c8966b4d01e239da1b9165e91aa9d",
+                "url": "https://api.github.com/repos/drupal/core-recommended/zipball/f043a94e9a8aa60016974d60648508258a51bf86",
+                "reference": "f043a94e9a8aa60016974d60648508258a51bf86",
                 "shasum": ""
             },
             "require": {
@@ -3362,7 +3362,7 @@
                 "doctrine/annotations": "1.13.1",
                 "doctrine/lexer": "1.2.1",
                 "doctrine/reflection": "1.2.2",
-                "drupal/core": "9.2.0",
+                "drupal/core": "9.2.1",
                 "egulias/email-validator": "2.1.25",
                 "guzzlehttp/guzzle": "6.5.5",
                 "guzzlehttp/promises": "1.4.1",
@@ -3418,7 +3418,7 @@
             "conflict": {
                 "webflo/drupal-core-strict": "*"
             },
-            "time": "2021-06-16T12:31:16+00:00",
+            "time": "2021-07-07T13:04:41+00:00",
             "type": "metapackage",
             "notification-url": "https://packagist.org/downloads/",
             "license": [
@@ -3426,7 +3426,7 @@
             ],
             "description": "Locked core dependencies; require this project INSTEAD OF drupal/core.",
             "support": {
-                "source": "https://github.com/drupal/core-recommended/tree/9.2.0"
+                "source": "https://github.com/drupal/core-recommended/tree/9.2.1"
             },
             "install-path": null
         },
diff --git a/vendor/composer/installed.php b/vendor/composer/installed.php
index f6678a4ac3..14d6b8564d 100644
--- a/vendor/composer/installed.php
+++ b/vendor/composer/installed.php
@@ -6,7 +6,7 @@
     'aliases' => 
     array (
     ),
-    'reference' => 'a89ed315c5f4d36ea9513b4dfeef27d25a4975ea',
+    'reference' => '481e21ac36751a525f541979c65002ec3bb47e05',
     'name' => 'osu-asc-webservices/d8-upstream',
   ),
   'versions' => 
@@ -274,7 +274,7 @@
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/addtocalendar' => 
@@ -308,7 +308,7 @@
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/allowed_formats' => 
@@ -333,28 +333,28 @@
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/ban' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/bartik' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/basic_auth' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/better_exposed_filters' => 
@@ -370,21 +370,21 @@
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/block' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/block_content' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/block_field' => 
@@ -418,7 +418,7 @@
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/bootstrap' => 
@@ -434,7 +434,7 @@
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/cache_control_override' => 
@@ -459,7 +459,7 @@
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/ckeditor_indentblock' => 
@@ -475,35 +475,35 @@
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/classy' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/color' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/comment' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/config' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/config_direct_save' => 
@@ -537,7 +537,7 @@
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/config_update' => 
@@ -589,7 +589,7 @@
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/content_access' => 
@@ -605,58 +605,58 @@
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/content_translation' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/contextual' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/core' => 
     array (
-      'pretty_version' => '9.2.0',
-      'version' => '9.2.0.0',
+      'pretty_version' => '9.2.1',
+      'version' => '9.2.1.0',
       'aliases' => 
       array (
       ),
-      'reference' => '0231ec3b5a195d39ab02680672736de781a59599',
+      'reference' => '20eb99aa59a265d22a21a4d6fde70901c3b5a37c',
     ),
     'drupal/core-annotation' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/core-assertion' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/core-bridge' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/core-class-finder' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/core-composer-scaffold' => 
@@ -672,156 +672,156 @@
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/core-dependency-injection' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/core-diff' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/core-discovery' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/core-event-dispatcher' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/core-file-cache' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/core-file-security' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/core-filesystem' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/core-front-matter' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/core-gettext' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/core-graph' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/core-http-foundation' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/core-php-storage' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/core-plugin' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/core-proxy-builder' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/core-recommended' => 
     array (
-      'pretty_version' => '9.2.0',
-      'version' => '9.2.0.0',
+      'pretty_version' => '9.2.1',
+      'version' => '9.2.1.0',
       'aliases' => 
       array (
       ),
-      'reference' => '436c459d1c9c8966b4d01e239da1b9165e91aa9d',
+      'reference' => 'f043a94e9a8aa60016974d60648508258a51bf86',
     ),
     'drupal/core-render' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/core-serialization' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/core-transliteration' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/core-utility' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/core-uuid' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/core-version' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/crop' => 
@@ -846,21 +846,21 @@
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/datetime_range' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/dblog' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/dropzonejs' => 
@@ -885,14 +885,14 @@
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/editor' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/editor_advanced_link' => 
@@ -962,7 +962,7 @@
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/entity_reference_revisions' => 
@@ -987,7 +987,7 @@
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/field_group' => 
@@ -1003,7 +1003,7 @@
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/field_permissions' => 
@@ -1019,14 +1019,14 @@
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/file' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/file_browser' => 
@@ -1042,7 +1042,7 @@
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/focal_point' => 
@@ -1058,7 +1058,7 @@
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/google_analytics' => 
@@ -1083,28 +1083,28 @@
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/help' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/help_topics' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/history' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/honeypot' => 
@@ -1120,7 +1120,7 @@
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/inline_entity_form' => 
@@ -1136,7 +1136,7 @@
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/jquery_ui' => 
@@ -1179,28 +1179,28 @@
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/language' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/layout_builder' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/layout_discovery' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/libraries' => 
@@ -1216,7 +1216,7 @@
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/link_attributes' => 
@@ -1241,7 +1241,7 @@
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/mathjax' => 
@@ -1257,7 +1257,7 @@
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/media_entity_browser' => 
@@ -1282,7 +1282,7 @@
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/menu_block' => 
@@ -1316,14 +1316,14 @@
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/menu_ui' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/metatag' => 
@@ -1339,7 +1339,7 @@
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/migrate_devel' => 
@@ -1355,21 +1355,21 @@
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/migrate_drupal_multilingual' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/migrate_drupal_ui' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/migrate_plus' => 
@@ -1394,7 +1394,7 @@
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/mobile_detect' => 
@@ -1437,28 +1437,28 @@
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/olivero' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/options' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/page_cache' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/pantheon_advanced_page_cache' => 
@@ -1483,14 +1483,14 @@
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/path_alias' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/pathauto' => 
@@ -1506,14 +1506,14 @@
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/rdf' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/rebuild_cache_access' => 
@@ -1556,14 +1556,14 @@
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/rest' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/roleassign' => 
@@ -1588,7 +1588,7 @@
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/search_api' => 
@@ -1613,28 +1613,28 @@
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/settings_tray' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/seven' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/shortcut' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/simple_gmap' => 
@@ -1704,21 +1704,21 @@
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/stark' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/statistics' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/superfish' => 
@@ -1743,35 +1743,35 @@
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/system' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/taxonomy' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/telephone' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/text' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/token' => 
@@ -1787,21 +1787,21 @@
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/tour' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/tracker' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/twig_tweak' => 
@@ -1826,14 +1826,14 @@
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/user' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/userprotect' => 
@@ -1867,7 +1867,7 @@
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/views_ajax_history' => 
@@ -1928,7 +1928,7 @@
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/webform' => 
@@ -1944,14 +1944,14 @@
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drupal/workspaces' => 
     array (
       'replaced' => 
       array (
-        0 => '9.2.0',
+        0 => '9.2.1',
       ),
     ),
     'drush-ops/behat-drush-endpoint' => 
@@ -2202,7 +2202,7 @@
       'aliases' => 
       array (
       ),
-      'reference' => 'a89ed315c5f4d36ea9513b4dfeef27d25a4975ea',
+      'reference' => '481e21ac36751a525f541979c65002ec3bb47e05',
     ),
     'pantheon-systems/quicksilver-pushback' => 
     array (
diff --git a/web/core/MAINTAINERS.txt b/web/core/MAINTAINERS.txt
index 14fbbe3a50..ff3ee093e0 100644
--- a/web/core/MAINTAINERS.txt
+++ b/web/core/MAINTAINERS.txt
@@ -260,8 +260,9 @@ JavaScript
 - Sally Young 'justafish' https://www.drupal.org/u/justafish
 
 JSON:API
-- Gabe Sullice 'gabesullice' https://www.drupal.org/u/gabesullice
 - Mateu Aguiló Bosch 'e0ipso' https://www.drupal.org/u/e0ipso
+- Björn Brala 'bbrala' https://www.drupal.org/u/bbrala
+- Gabe Sullice 'gabesullice' https://www.drupal.org/u/gabesullice
 - Wim Leers 'Wim Leers' https://www.drupal.org/u/wim-leers
 
 Language
@@ -520,7 +521,6 @@ their responsibilities. The initiative coordinators are:
 
 Decoupled Menus Initiative
 - Théodore Biadala 'nod_' https://www.drupal.org/u/nod_
-- Gabe Sullice 'gabesullice' https://www.drupal.org/u/gabesullice
 
 Media Initiative
 - Janez Urevc 'slashrsm' https://www.drupal.org/u/slashrsm
diff --git a/web/core/lib/Drupal.php b/web/core/lib/Drupal.php
index f14bf77bef..18b78df308 100644
--- a/web/core/lib/Drupal.php
+++ b/web/core/lib/Drupal.php
@@ -75,7 +75,7 @@ class Drupal {
   /**
    * The current system version.
    */
-  const VERSION = '9.2.0';
+  const VERSION = '9.2.1';
 
   /**
    * Core API compatibility.
diff --git a/web/core/lib/Drupal/Component/Utility/UserAgent.php b/web/core/lib/Drupal/Component/Utility/UserAgent.php
index c80c44e19d..934049033c 100644
--- a/web/core/lib/Drupal/Component/Utility/UserAgent.php
+++ b/web/core/lib/Drupal/Component/Utility/UserAgent.php
@@ -40,9 +40,11 @@ public static function getBestMatchingLangcode($http_accept_language, $langcodes
     // The Accept-Language header contains information about the language
     // preferences configured in the user's user agent / operating system.
     // RFC 2616 (section 14.4) defines the Accept-Language header as follows:
+    // @code
     //   Accept-Language = "Accept-Language" ":"
     //                  1#( language-range [ ";" "q" "=" qvalue ] )
     //   language-range  = ( ( 1*8ALPHA *( "-" 1*8ALPHA ) ) | "*" )
+    // @endcode
     // Samples: "hu, en-us;q=0.66, en;q=0.33", "hu,en-us;q=0.5"
     $ua_langcodes = [];
     if (preg_match_all('@(?<=[, ]|^)([a-zA-Z-]+|\*)(?:;q=([0-9.]+))?(?:$|\s*,\s*)@', trim($http_accept_language), $matches, PREG_SET_ORDER)) {
diff --git a/web/core/lib/Drupal/Core/Config/ConfigImporter.php b/web/core/lib/Drupal/Core/Config/ConfigImporter.php
index 3340f6e654..4d998fa959 100644
--- a/web/core/lib/Drupal/Core/Config/ConfigImporter.php
+++ b/web/core/lib/Drupal/Core/Config/ConfigImporter.php
@@ -393,17 +393,19 @@ protected function createExtensionChangelist() {
     // dependencies are uninstalled last. Extensions of the same weight are
     // sorted in reverse alphabetical order, to ensure the order is exactly
     // opposite from installation. For example, this module list:
+    // @code
     // array(
     //   'actions' => 0,
     //   'ban' => 0,
     //   'options' => -2,
     //   'text' => -1,
     // );
+    // @endcode
     // will result in the following sort order:
-    // -2   options
-    // -1   text
-    //  0 0 ban
-    //  0 1 actions
+    // 1. -2   options
+    // 2. -1   text
+    // 3.  0 0 ban
+    // 4.  0 1 actions
     // @todo Move this sorting functionality to the extension system.
     array_multisort(array_values($module_list), SORT_ASC, array_keys($module_list), SORT_DESC, $module_list);
     $this->extensionChangelist['module']['uninstall'] = array_intersect(array_keys($module_list), $uninstall);
diff --git a/web/core/lib/Drupal/Core/Database/Connection.php b/web/core/lib/Drupal/Core/Database/Connection.php
index e61c51db7b..dcec7755cf 100644
--- a/web/core/lib/Drupal/Core/Database/Connection.php
+++ b/web/core/lib/Drupal/Core/Database/Connection.php
@@ -1123,10 +1123,10 @@ public function exceptionHandler() {
   /**
    * Prepares and returns a SELECT query object.
    *
-   * @param string $table
-   *   The base table for this query, that is, the first table in the FROM
-   *   clause. This table will also be used as the "base" table for query_alter
-   *   hook implementations.
+   * @param string|\Drupal\Core\Database\Query\SelectInterface $table
+   *   The base table name or subquery for this query, used in the FROM clause.
+   *   If a string, the table specified will also be used as the "base" table
+   *   for query_alter hook implementations.
    * @param string $alias
    *   (optional) The alias of the base table of this query.
    * @param $options
diff --git a/web/core/lib/Drupal/Core/Database/Query/Select.php b/web/core/lib/Drupal/Core/Database/Query/Select.php
index 94cbf92b14..8a86723675 100644
--- a/web/core/lib/Drupal/Core/Database/Query/Select.php
+++ b/web/core/lib/Drupal/Core/Database/Query/Select.php
@@ -123,8 +123,8 @@ class Select extends Query implements SelectInterface {
    *
    * @param \Drupal\Core\Database\Connection $connection
    *   Database connection object.
-   * @param string $table
-   *   The name of the table that is being queried.
+   * @param string|\Drupal\Core\Database\Query\SelectInterface $table
+   *   The table name or subquery that is being queried.
    * @param string $alias
    *   The alias for the table.
    * @param array $options
diff --git a/web/core/lib/Drupal/Core/DrupalKernel.php b/web/core/lib/Drupal/Core/DrupalKernel.php
index 3eee8d871c..c6db31ff3b 100644
--- a/web/core/lib/Drupal/Core/DrupalKernel.php
+++ b/web/core/lib/Drupal/Core/DrupalKernel.php
@@ -459,7 +459,7 @@ public function boot() {
     // Provide a default configuration, if not set.
     if (!isset($configuration['default'])) {
       // @todo Use extension_loaded('apcu') for non-testbot
-      //  https://www.drupal.org/node/2447753.
+      //   https://www.drupal.org/node/2447753.
       if (function_exists('apcu_fetch')) {
         $configuration['default']['cache_backend_class'] = '\Drupal\Component\FileCache\ApcuFileCacheBackend';
       }
diff --git a/web/core/lib/Drupal/Core/Entity/ContentEntityBase.php b/web/core/lib/Drupal/Core/Entity/ContentEntityBase.php
index 35dca9a9c6..3e82c6f95f 100644
--- a/web/core/lib/Drupal/Core/Entity/ContentEntityBase.php
+++ b/web/core/lib/Drupal/Core/Entity/ContentEntityBase.php
@@ -1434,7 +1434,7 @@ public function hasTranslationChanges() {
 
     foreach ($this->getFieldDefinitions() as $field_name => $definition) {
       // @todo Avoid special-casing the following fields. See
-      //    https://www.drupal.org/node/2329253.
+      //   https://www.drupal.org/node/2329253.
       if (in_array($field_name, $skip_fields, TRUE) || ($skip_untranslatable_fields && !$definition->isTranslatable())) {
         continue;
       }
diff --git a/web/core/lib/Drupal/Core/Entity/EntityFieldManager.php b/web/core/lib/Drupal/Core/Entity/EntityFieldManager.php
index 916a4dcac0..c845942612 100644
--- a/web/core/lib/Drupal/Core/Entity/EntityFieldManager.php
+++ b/web/core/lib/Drupal/Core/Entity/EntityFieldManager.php
@@ -275,7 +275,7 @@ protected function buildBaseFieldDefinitions($entity_type_id) {
     $provider = $entity_type->getProvider();
     foreach ($base_field_definitions as $definition) {
       // @todo Remove this check once FieldDefinitionInterface exposes a proper
-      //  provider setter. See https://www.drupal.org/node/2225961.
+      //   provider setter. See https://www.drupal.org/node/2225961.
       if ($definition instanceof BaseFieldDefinition) {
         $definition->setProvider($provider);
       }
@@ -289,7 +289,7 @@ protected function buildBaseFieldDefinitions($entity_type_id) {
         // defining the field.
         foreach ($module_definitions as $field_name => $definition) {
           // @todo Remove this check once FieldDefinitionInterface exposes a
-          //  proper provider setter. See https://www.drupal.org/node/2225961.
+          //   proper provider setter. See https://www.drupal.org/node/2225961.
           if ($definition instanceof BaseFieldDefinition && $definition->getProvider() == NULL) {
             $definition->setProvider($module);
           }
@@ -397,7 +397,7 @@ protected function buildBundleFieldDefinitions($entity_type_id, $bundle, array $
     $provider = $entity_type->getProvider();
     foreach ($bundle_field_definitions as $definition) {
       // @todo Remove this check once FieldDefinitionInterface exposes a proper
-      //  provider setter. See https://www.drupal.org/node/2225961.
+      //   provider setter. See https://www.drupal.org/node/2225961.
       if ($definition instanceof BaseFieldDefinition) {
         $definition->setProvider($provider);
       }
@@ -411,7 +411,7 @@ protected function buildBundleFieldDefinitions($entity_type_id, $bundle, array $
         // defining the field.
         foreach ($module_definitions as $field_name => $definition) {
           // @todo Remove this check once FieldDefinitionInterface exposes a
-          //  proper provider setter. See https://www.drupal.org/node/2225961.
+          //   proper provider setter. See https://www.drupal.org/node/2225961.
           if ($definition instanceof BaseFieldDefinition) {
             $definition->setProvider($module);
           }
@@ -587,7 +587,7 @@ protected function buildFieldStorageDefinitions($entity_type_id) {
         // defining the field.
         foreach ($module_definitions as $field_name => $definition) {
           // @todo Remove this check once FieldDefinitionInterface exposes a
-          //  proper provider setter. See https://www.drupal.org/node/2225961.
+          //   proper provider setter. See https://www.drupal.org/node/2225961.
           if ($definition instanceof BaseFieldDefinition) {
             $definition->setProvider($module);
             $definition->setName($field_name);
diff --git a/web/core/lib/Drupal/Core/Entity/EntityForm.php b/web/core/lib/Drupal/Core/Entity/EntityForm.php
index 3056062df2..a29c392de9 100644
--- a/web/core/lib/Drupal/Core/Entity/EntityForm.php
+++ b/web/core/lib/Drupal/Core/Entity/EntityForm.php
@@ -324,7 +324,7 @@ protected function copyFormValuesToEntity(EntityInterface $entity, array $form,
       $values = array_diff_key($values, $this->entity->getPluginCollections());
     }
 
-    // @todo: This relies on a method that only exists for config and content
+    // @todo This relies on a method that only exists for config and content
     //   entities, in a different way. Consider moving this logic to a config
     //   entity specific implementation.
     foreach ($values as $key => $value) {
diff --git a/web/core/lib/Drupal/Core/Entity/EntityViewBuilder.php b/web/core/lib/Drupal/Core/Entity/EntityViewBuilder.php
index cc883b25cf..9ac0a6f557 100644
--- a/web/core/lib/Drupal/Core/Entity/EntityViewBuilder.php
+++ b/web/core/lib/Drupal/Core/Entity/EntityViewBuilder.php
@@ -292,7 +292,7 @@ public function buildMultiple(array $build_list) {
         $this->alterBuild($build_list[$key], $entity, $display, $view_mode);
 
         // Assign the weights configured in the display.
-        // @todo: Once https://www.drupal.org/node/1875974 provides the missing
+        // @todo Once https://www.drupal.org/node/1875974 provides the missing
         //   API, only do it for 'extra fields', since other components have
         //   been taken care of in EntityViewDisplay::buildMultiple().
         foreach ($display->getComponents() as $name => $options) {
diff --git a/web/core/lib/Drupal/Core/Entity/Routing/DefaultHtmlRouteProvider.php b/web/core/lib/Drupal/Core/Entity/Routing/DefaultHtmlRouteProvider.php
index 1f7fd6d07e..4dbd1d1bfe 100644
--- a/web/core/lib/Drupal/Core/Entity/Routing/DefaultHtmlRouteProvider.php
+++ b/web/core/lib/Drupal/Core/Entity/Routing/DefaultHtmlRouteProvider.php
@@ -155,7 +155,7 @@ protected function getAddFormRoute(EntityTypeInterface $entity_type) {
       // If the entity has bundles, we can provide a bundle-specific title
       // and access requirements.
       $expected_parameter = $entity_type->getBundleEntityType() ?: $entity_type->getKey('bundle');
-      // @todo: We have to check if a route contains a bundle in its path as
+      // @todo We have to check if a route contains a bundle in its path as
       //   test entities have inconsistent usage of "add-form" link templates.
       //   Fix it in https://www.drupal.org/node/2699959.
       if (($bundle_key = $entity_type->getKey('bundle')) && strpos($route->getPath(), '{' . $expected_parameter . '}') !== FALSE) {
diff --git a/web/core/lib/Drupal/Core/EventSubscriber/ActiveLinkResponseFilter.php b/web/core/lib/Drupal/Core/EventSubscriber/ActiveLinkResponseFilter.php
index 1d7234eed6..4e530cf31b 100644
--- a/web/core/lib/Drupal/Core/EventSubscriber/ActiveLinkResponseFilter.php
+++ b/web/core/lib/Drupal/Core/EventSubscriber/ActiveLinkResponseFilter.php
@@ -180,7 +180,7 @@ public static function setLinkActiveClass($html_markup, $current_path, $is_front
       }
 
       // Get the HTML: this will be the opening part of a single tag, e.g.:
-      //   <a href="/" data-drupal-link-system-path="&lt;front&gt;">
+      // <a href="/" data-drupal-link-system-path="&lt;front&gt;">
       $tag = substr($html_markup, $pos_tag_start, $pos_tag_end - $pos_tag_start + 1);
 
       // Parse it into a DOMDocument so we can reliably read and modify
diff --git a/web/core/lib/Drupal/Core/Extension/ModuleInstaller.php b/web/core/lib/Drupal/Core/Extension/ModuleInstaller.php
index 87c7a90516..752c4251e8 100644
--- a/web/core/lib/Drupal/Core/Extension/ModuleInstaller.php
+++ b/web/core/lib/Drupal/Core/Extension/ModuleInstaller.php
@@ -504,12 +504,12 @@ public function uninstall(array $module_list, $uninstall_dependents = TRUE) {
       // into its statically cached list.
       \Drupal::service('extension.list.module')->reset();
 
-      // Clear plugin manager caches.
-      \Drupal::getContainer()->get('plugin.cache_clearer')->clearCachedDefinitions();
-
       // Update the kernel to exclude the uninstalled modules.
       $this->updateKernel($module_filenames);
 
+      // Clear plugin manager caches.
+      \Drupal::getContainer()->get('plugin.cache_clearer')->clearCachedDefinitions();
+
       // Update the theme registry to remove the newly uninstalled module.
       drupal_theme_rebuild();
 
diff --git a/web/core/lib/Drupal/Core/File/MimeType/ExtensionMimeTypeGuesser.php b/web/core/lib/Drupal/Core/File/MimeType/ExtensionMimeTypeGuesser.php
index b0798000aa..d8ec405542 100644
--- a/web/core/lib/Drupal/Core/File/MimeType/ExtensionMimeTypeGuesser.php
+++ b/web/core/lib/Drupal/Core/File/MimeType/ExtensionMimeTypeGuesser.php
@@ -913,9 +913,9 @@ public function guessMimeType($path): ?string {
 
     // Iterate over the file parts, trying to find a match.
     // For my.awesome.image.jpeg, we try:
-    //   - jpeg
-    //   - image.jpeg, and
-    //   - awesome.image.jpeg
+    // - jpeg
+    // - image.jpeg, and
+    // - awesome.image.jpeg
     while ($additional_part = array_pop($file_parts)) {
       $extension = strtolower($additional_part . ($extension ? '.' . $extension : ''));
       if (isset($this->mapping['extensions'][$extension])) {
diff --git a/web/core/lib/Drupal/Core/Form/FormState.php b/web/core/lib/Drupal/Core/Form/FormState.php
index 8264371c83..e52ac64677 100644
--- a/web/core/lib/Drupal/Core/Form/FormState.php
+++ b/web/core/lib/Drupal/Core/Form/FormState.php
@@ -1206,8 +1206,11 @@ public function cleanValues() {
       // the value corresponding to this button.
       // We iterate over the #parents of this button and move a reference to
       // each parent in self::getValues(). For example, if #parents is:
+      // @code
       //   array('foo', 'bar', 'baz')
+      // @endcode
       // then the corresponding self::getValues() part will look like this:
+      // @code
       // array(
       //   'foo' => array(
       //     'bar' => array(
@@ -1215,6 +1218,7 @@ public function cleanValues() {
       //     ),
       //   ),
       // )
+      // @endcode
       // We start by (re)moving 'baz' to $last_parent, so we are able unset it
       // at the end of the iteration. Initially, $values will contain a
       // reference to self::getValues(), but in the iteration we move the
diff --git a/web/core/lib/Drupal/Core/Form/FormSubmitter.php b/web/core/lib/Drupal/Core/Form/FormSubmitter.php
index f3260e2fad..a3d116db05 100644
--- a/web/core/lib/Drupal/Core/Form/FormSubmitter.php
+++ b/web/core/lib/Drupal/Core/Form/FormSubmitter.php
@@ -101,7 +101,7 @@ public function executeSubmitHandlers(&$form, FormStateInterface &$form_state) {
       // Check if a previous _submit handler has set a batch, but make sure we
       // do not react to a batch that is already being processed (for instance
       // if a batch operation performs a
-      //  \Drupal\Core\Form\FormBuilderInterface::submitForm()).
+      // \Drupal\Core\Form\FormBuilderInterface::submitForm()).
       if (($batch = &$this->batchGet()) && !isset($batch['id'])) {
         // Some previous submit handler has set a batch. To ensure correct
         // execution order, store the call in a special 'control' batch set.
diff --git a/web/core/lib/Drupal/Core/Render/RenderCache.php b/web/core/lib/Drupal/Core/Render/RenderCache.php
index 20e4b0c142..e25b5f795d 100644
--- a/web/core/lib/Drupal/Core/Render/RenderCache.php
+++ b/web/core/lib/Drupal/Core/Render/RenderCache.php
@@ -62,7 +62,7 @@ public function get(array $elements) {
     // Form submissions rely on the form being built during the POST request,
     // and render caching of forms prevents this from happening.
     // @todo remove the isMethodCacheable() check when
-    //       https://www.drupal.org/node/2367555 lands.
+    //   https://www.drupal.org/node/2367555 lands.
     if (!$this->requestStack->getCurrentRequest()->isMethodCacheable() || !$cid = $this->createCacheID($elements)) {
       return FALSE;
     }
@@ -89,7 +89,7 @@ public function set(array &$elements, array $pre_bubbling_elements) {
     // Form submissions rely on the form being built during the POST request,
     // and render caching of forms prevents this from happening.
     // @todo remove the isMethodCacheable() check when
-    //       https://www.drupal.org/node/2367555 lands.
+    //   https://www.drupal.org/node/2367555 lands.
     if (!$this->requestStack->getCurrentRequest()->isMethodCacheable() || !$cid = $this->createCacheID($elements)) {
       return FALSE;
     }
@@ -120,6 +120,7 @@ public function set(array &$elements, array $pre_bubbling_elements) {
       // were specified by all children, so what we need is a way to
       // persist that information between the cache write and the next cache
       // read. So, what we can do is store the following into 'foo':
+      // @code
       // [
       //   '#cache_redirect' => TRUE,
       //   '#cache' => [
@@ -127,6 +128,7 @@ public function set(array &$elements, array $pre_bubbling_elements) {
       //     'contexts' => ['b'],
       //   ],
       // ]
+      // @endcode
       //
       // This efficiently lets cacheGet() redirect to a $cid that includes all
       // of the required contexts. The strategy is on-demand: in the case where
@@ -152,6 +154,7 @@ public function set(array &$elements, array $pre_bubbling_elements) {
       // following:
       // - When a request is processed where context 'b' = 'b1', what would be
       //   cached for a $pre_bubbling_cid of 'foo' is:
+      // @code
       //   [
       //     '#cache_redirect' => TRUE,
       //     '#cache' => [
@@ -159,12 +162,14 @@ public function set(array &$elements, array $pre_bubbling_elements) {
       //       'contexts' => ['b', 'c'],
       //     ],
       //   ]
+      // @endcode
       // - When a request is processed where context 'b' = 'b2', we would
       //   retrieve the above from cache, but when following that redirection,
       //   get a cache miss, since we're processing a 'b' context value that
       //   has not yet been cached. Given the cache miss, we would continue
       //   with rendering the structure, perform the required context bubbling
       //   and then overwrite the above item with:
+      // @code
       //   [
       //     '#cache_redirect' => TRUE,
       //     '#cache' => [
@@ -172,11 +177,13 @@ public function set(array &$elements, array $pre_bubbling_elements) {
       //       'contexts' => ['b', 'd'],
       //     ],
       //   ]
+      // @endcode
       // - Now, if a request comes in where context 'b' = 'b1' again, the above
       //   would redirect to a cache key that doesn't exist, since we have not
       //   yet cached an item that includes 'b'='b1' and something for 'd'. So
       //   we would process this request as a cache miss, at the end of which,
       //   we would overwrite the above item back to:
+      // @code
       //   [
       //     '#cache_redirect' => TRUE,
       //     '#cache' => [
@@ -184,6 +191,7 @@ public function set(array &$elements, array $pre_bubbling_elements) {
       //       'contexts' => ['b', 'c'],
       //     ],
       //   ]
+      // @endcode
       // - The above would always result in accurate renderings, but would
       //   result in poor performance as we keep processing requests as cache
       //   misses even though the target of the redirection is cached, and
@@ -193,6 +201,7 @@ public function set(array &$elements, array $pre_bubbling_elements) {
       // A way to resolve the ping-pong problem is to eventually reach a cache
       // state where the redirection element includes all of the contexts used
       // throughout all requests:
+      // @code
       // [
       //   '#cache_redirect' => TRUE,
       //   '#cache' => [
@@ -200,6 +209,7 @@ public function set(array &$elements, array $pre_bubbling_elements) {
       //     'contexts' => ['b', 'c', 'd'],
       //   ],
       // ]
+      // @endcode
       //
       // We can't reach that state right away, since we don't know what the
       // result of future requests will be, but we can incrementally move
diff --git a/web/core/lib/Drupal/Core/Render/Renderer.php b/web/core/lib/Drupal/Core/Render/Renderer.php
index 6efede10ee..25b294c665 100644
--- a/web/core/lib/Drupal/Core/Render/Renderer.php
+++ b/web/core/lib/Drupal/Core/Render/Renderer.php
@@ -344,7 +344,7 @@ protected function doRender(&$elements, $is_root_call = FALSE) {
     // present (without such a callback, it would be impossible to replace the
     // placeholder), replace the current element with a placeholder.
     // @todo remove the isMethodCacheable() check when
-    //       https://www.drupal.org/node/2367555 lands.
+    //   https://www.drupal.org/node/2367555 lands.
     if (isset($elements['#create_placeholder']) && $elements['#create_placeholder'] === TRUE && $this->requestStack->getCurrentRequest()->isMethodCacheable()) {
       if (!isset($elements['#lazy_builder'])) {
         throw new \LogicException('When #create_placeholder is set, a #lazy_builder callback must be present as well.');
diff --git a/web/core/lib/Drupal/Core/StreamWrapper/LocalStream.php b/web/core/lib/Drupal/Core/StreamWrapper/LocalStream.php
index f9a57ab30f..7cef6cb4c9 100644
--- a/web/core/lib/Drupal/Core/StreamWrapper/LocalStream.php
+++ b/web/core/lib/Drupal/Core/StreamWrapper/LocalStream.php
@@ -144,21 +144,7 @@ protected function getLocalPath($uri = NULL) {
   }
 
   /**
-   * Support for fopen(), file_get_contents(), file_put_contents() etc.
-   *
-   * @param string $uri
-   *   A string containing the URI to the file to open.
-   * @param int $mode
-   *   The file mode ("r", "wb" etc.).
-   * @param int $options
-   *   A bit mask of STREAM_USE_PATH and STREAM_REPORT_ERRORS.
-   * @param string $opened_path
-   *   A string containing the path actually opened.
-   *
-   * @return bool
-   *   Returns TRUE if file was opened successfully.
-   *
-   * @see http://php.net/manual/streamwrapper.stream-open.php
+   * {@inheritdoc}
    */
   public function stream_open($uri, $mode, $options, &$opened_path) {
     $this->uri = $uri;
@@ -179,20 +165,7 @@ public function stream_open($uri, $mode, $options, &$opened_path) {
   }
 
   /**
-   * Support for flock().
-   *
-   * @param int $operation
-   *   One of the following:
-   *   - LOCK_SH to acquire a shared lock (reader).
-   *   - LOCK_EX to acquire an exclusive lock (writer).
-   *   - LOCK_UN to release a lock (shared or exclusive).
-   *   - LOCK_NB if you don't want flock() to block while locking (not
-   *     supported on Windows).
-   *
-   * @return bool
-   *   Always returns TRUE at the present time.
-   *
-   * @see http://php.net/manual/streamwrapper.stream-lock.php
+   * {@inheritdoc}
    */
   public function stream_lock($operation) {
     if (in_array($operation, [LOCK_SH, LOCK_EX, LOCK_UN, LOCK_NB])) {
@@ -203,42 +176,21 @@ public function stream_lock($operation) {
   }
 
   /**
-   * Support for fread(), file_get_contents() etc.
-   *
-   * @param int $count
-   *   Maximum number of bytes to be read.
-   *
-   * @return string|bool
-   *   The string that was read, or FALSE in case of an error.
-   *
-   * @see http://php.net/manual/streamwrapper.stream-read.php
+   * {@inheritdoc}
    */
   public function stream_read($count) {
     return fread($this->handle, $count);
   }
 
   /**
-   * Support for fwrite(), file_put_contents() etc.
-   *
-   * @param string $data
-   *   The string to be written.
-   *
-   * @return int
-   *   The number of bytes written.
-   *
-   * @see http://php.net/manual/streamwrapper.stream-write.php
+   * {@inheritdoc}
    */
   public function stream_write($data) {
     return fwrite($this->handle, $data);
   }
 
   /**
-   * Support for feof().
-   *
-   * @return bool
-   *   TRUE if end-of-file has been reached.
-   *
-   * @see http://php.net/manual/streamwrapper.stream-eof.php
+   * {@inheritdoc}
    */
   public function stream_eof() {
     return feof($this->handle);
@@ -254,49 +206,28 @@ public function stream_seek($offset, $whence = SEEK_SET) {
   }
 
   /**
-   * Support for fflush().
-   *
-   * @return bool
-   *   TRUE if data was successfully stored (or there was no data to store).
-   *
-   * @see http://php.net/manual/streamwrapper.stream-flush.php
+   * {@inheritdoc}
    */
   public function stream_flush() {
     return fflush($this->handle);
   }
 
   /**
-   * Support for ftell().
-   *
-   * @return bool
-   *   The current offset in bytes from the beginning of file.
-   *
-   * @see http://php.net/manual/streamwrapper.stream-tell.php
+   * {@inheritdoc}
    */
   public function stream_tell() {
     return ftell($this->handle);
   }
 
   /**
-   * Support for fstat().
-   *
-   * @return bool
-   *   An array with file status, or FALSE in case of an error - see fstat()
-   *   for a description of this array.
-   *
-   * @see http://php.net/manual/streamwrapper.stream-stat.php
+   * {@inheritdoc}
    */
   public function stream_stat() {
     return fstat($this->handle);
   }
 
   /**
-   * Support for fclose().
-   *
-   * @return bool
-   *   TRUE if stream was successfully closed.
-   *
-   * @see http://php.net/manual/streamwrapper.stream-close.php
+   * {@inheritdoc}
    */
   public function stream_close() {
     return fclose($this->handle);
@@ -368,15 +299,7 @@ public function stream_truncate($new_size) {
   }
 
   /**
-   * Support for unlink().
-   *
-   * @param string $uri
-   *   A string containing the URI to the resource to delete.
-   *
-   * @return bool
-   *   TRUE if resource was successfully deleted.
-   *
-   * @see http://php.net/manual/streamwrapper.unlink.php
+   * {@inheritdoc}
    */
   public function unlink($uri) {
     $this->uri = $uri;
@@ -384,36 +307,14 @@ public function unlink($uri) {
   }
 
   /**
-   * Support for rename().
-   *
-   * @param string $from_uri
-   *   The URI to the file to rename.
-   * @param string $to_uri
-   *   The new URI for file.
-   *
-   * @return bool
-   *   TRUE if file was successfully renamed.
-   *
-   * @see http://php.net/manual/streamwrapper.rename.php
+   * {@inheritdoc}
    */
   public function rename($from_uri, $to_uri) {
     return rename($this->getLocalPath($from_uri), $this->getLocalPath($to_uri));
   }
 
   /**
-   * Gets the name of the directory from a given path.
-   *
-   * This method is usually accessed through
-   * \Drupal\Core\File\FileSystemInterface::dirname(), which wraps around the
-   * PHP dirname() function because it does not support stream wrappers.
-   *
-   * @param string $uri
-   *   A URI or path.
-   *
-   * @return string
-   *   A string containing the directory name.
-   *
-   * @see \Drupal\Core\File\FileSystemInterface::dirname()
+   * {@inheritdoc}
    */
   public function dirname($uri = NULL) {
     list($scheme) = explode('://', $uri, 2);
@@ -428,19 +329,7 @@ public function dirname($uri = NULL) {
   }
 
   /**
-   * Support for mkdir().
-   *
-   * @param string $uri
-   *   A string containing the URI to the directory to create.
-   * @param int $mode
-   *   Permission flags - see mkdir().
-   * @param int $options
-   *   A bit mask of STREAM_REPORT_ERRORS and STREAM_MKDIR_RECURSIVE.
-   *
-   * @return bool
-   *   TRUE if directory was successfully created.
-   *
-   * @see http://php.net/manual/streamwrapper.mkdir.php
+   * {@inheritdoc}
    */
   public function mkdir($uri, $mode, $options) {
     $this->uri = $uri;
@@ -464,17 +353,7 @@ public function mkdir($uri, $mode, $options) {
   }
 
   /**
-   * Support for rmdir().
-   *
-   * @param string $uri
-   *   A string containing the URI to the directory to delete.
-   * @param int $options
-   *   A bit mask of STREAM_REPORT_ERRORS.
-   *
-   * @return bool
-   *   TRUE if directory was successfully removed.
-   *
-   * @see http://php.net/manual/streamwrapper.rmdir.php
+   * {@inheritdoc}
    */
   public function rmdir($uri, $options) {
     $this->uri = $uri;
@@ -489,18 +368,7 @@ public function rmdir($uri, $options) {
   }
 
   /**
-   * Support for stat().
-   *
-   * @param string $uri
-   *   A string containing the URI to get information about.
-   * @param int $flags
-   *   A bit mask of STREAM_URL_STAT_LINK and STREAM_URL_STAT_QUIET.
-   *
-   * @return array
-   *   An array with file status, or FALSE in case of an error - see fstat()
-   *   for a description of this array.
-   *
-   * @see http://php.net/manual/streamwrapper.url-stat.php
+   * {@inheritdoc}
    */
   public function url_stat($uri, $flags) {
     $this->uri = $uri;
@@ -516,17 +384,7 @@ public function url_stat($uri, $flags) {
   }
 
   /**
-   * Support for opendir().
-   *
-   * @param string $uri
-   *   A string containing the URI to the directory to open.
-   * @param int $options
-   *   Unknown (parameter is not documented in PHP Manual).
-   *
-   * @return bool
-   *   TRUE on success.
-   *
-   * @see http://php.net/manual/streamwrapper.dir-opendir.php
+   * {@inheritdoc}
    */
   public function dir_opendir($uri, $options) {
     $this->uri = $uri;
@@ -536,24 +394,14 @@ public function dir_opendir($uri, $options) {
   }
 
   /**
-   * Support for readdir().
-   *
-   * @return string
-   *   The next filename, or FALSE if there are no more files in the directory.
-   *
-   * @see http://php.net/manual/streamwrapper.dir-readdir.php
+   * {@inheritdoc}
    */
   public function dir_readdir() {
     return readdir($this->handle);
   }
 
   /**
-   * Support for rewinddir().
-   *
-   * @return bool
-   *   TRUE on success.
-   *
-   * @see http://php.net/manual/streamwrapper.dir-rewinddir.php
+   * {@inheritdoc}
    */
   public function dir_rewinddir() {
     rewinddir($this->handle);
@@ -564,12 +412,7 @@ public function dir_rewinddir() {
   }
 
   /**
-   * Support for closedir().
-   *
-   * @return bool
-   *   TRUE on success.
-   *
-   * @see http://php.net/manual/streamwrapper.dir-closedir.php
+   * {@inheritdoc}
    */
   public function dir_closedir() {
     closedir($this->handle);
diff --git a/web/core/lib/Drupal/Core/StreamWrapper/PhpStreamWrapperInterface.php b/web/core/lib/Drupal/Core/StreamWrapper/PhpStreamWrapperInterface.php
index 4c11c8d666..bce663ee0e 100644
--- a/web/core/lib/Drupal/Core/StreamWrapper/PhpStreamWrapperInterface.php
+++ b/web/core/lib/Drupal/Core/StreamWrapper/PhpStreamWrapperInterface.php
@@ -10,37 +10,144 @@
 interface PhpStreamWrapperInterface {
 
   /**
+   * Close directory handle.
+   *
+   * This method is called in response to closedir(). Any resources which were
+   * locked, or allocated, during opening and use of the directory stream
+   * should be released.
+   *
    * @return bool
+   *   Returns TRUE on success or FALSE on failure.
+   *
+   * @see closedir()
+   * @see http://php.net/manual/en/streamwrapper.dir-closedir.php
    */
   public function dir_closedir();
 
   /**
+   * Open directory handle.
+   *
+   * This method is called in response to opendir().
+   *
+   * @param string $path
+   *   Specifies the URL that was passed to opendir().
+   * @param int $options
+   *   Whether or not to enforce safe_mode (0x04).
+   *
    * @return bool
+   *   Returns TRUE on success or FALSE on failure.
+   *
+   * @see opendir()
+   * @see http://php.net/manual/en/streamwrapper.dir-opendir.php
    */
   public function dir_opendir($path, $options);
 
   /**
-   * @return string
+   * Read entry from directory handle.
+   *
+   * This method is called in response to readdir().
+   *
+   * @return string|false
+   *   Should return string representing the next filename, or FALSE if there
+   *   is no next file. Note, the return value will be casted to string.
+   *
+   * @see readdir()
+   * @see http://php.net/manual/en/streamwrapper.dir-readdir.php
    */
   public function dir_readdir();
 
   /**
+   * Rewind directory handle.
+   *
+   * This method is called in response to rewinddir(). Should reset the output
+   * generated by PhpStreamWrapperInterface::dir_readdir. The next call to
+   * PhpStreamWrapperInterface::dir_readdir should return the first entry in the
+   * location returned by PhpStreamWrapperInterface::dir_opendir.
+   *
    * @return bool
+   *   Returns TRUE on success or FALSE on failure.
+   *
+   * @see rewinddir()
+   * @see PhpStreamWrapperInterface::dir_readdir()
+   * @see http://php.net/manual/en/streamwrapper.dir-rewinddir.php
    */
   public function dir_rewinddir();
 
   /**
+   * Create a directory.
+   *
+   * This method is called in response to mkdir()
+   *
+   * Note, in order for the appropriate error message to be returned this method
+   * should not be defined if the wrapper does not support creating directories.
+   *
+   * Note, the streamWrapper::$context property is updated if a valid context is
+   * passed to the caller function.
+   *
+   * @param string $path
+   *   Directory which should be created.
+   * @param int $mode
+   *   The value passed to mkdir().
+   * @param int $options
+   *   A bitwise mask of values, such as STREAM_MKDIR_RECURSIVE.
+   *
    * @return bool
+   *   Returns TRUE on success or FALSE on failure.
+   *
+   * @see mkdir()
+   * @see PhpStreamWrapperInterface::rmdir()
+   * @see http://php.net/manual/en/streamwrapper.mkdir.php
    */
   public function mkdir($path, $mode, $options);
 
   /**
+   * Renames a file or directory.
+   *
+   * This method is called in response to rename(). Should attempt to rename
+   * $path_from to $path_to.
+   *
+   * Note, in order for the appropriate error message to be returned this method
+   * should not be defined if the wrapper does not support renaming files.
+   *
+   * Note, the streamWrapper::$context property is updated if a valid context is
+   * passed to the caller function.
+   *
+   * @param string $path_from
+   *   The URL to the current file.
+   * @param string $path_to
+   *   The URL which the $path_from should be renamed to.
+   *
    * @return bool
+   *   Returns TRUE on success or FALSE on failure.
+   *
+   * @see rename()
+   * @see http://php.net/manual/en/streamwrapper.rename.php
    */
   public function rename($path_from, $path_to);
 
   /**
+   * Removes a directory.
+   *
+   * This method is called in response to rmdir().
+   *
+   * Note, in order for the appropriate error message to be returned this method
+   * should not be defined if the wrapper does not support removing directories.
+   *
+   * Note, the streamWrapper::$context property is updated if a valid context is
+   * passed to the caller function.
+   *
+   * @param string $path
+   *   The directory URL which should be removed.
+   * @param int $options
+   *   A bitwise mask of values, such as STREAM_MKDIR_RECURSIVE.
+   *
    * @return bool
+   *   Returns TRUE on success or FALSE on failure.
+   *
+   * @see rmdir()
+   * @see PhpStreamWrapperInterface::mkdir()
+   * @see PhpStreamWrapperInterface::unlink()
+   * @see http://php.net/manual/en/streamwrapper.rmdir.php
    */
   public function rmdir($path, $options);
 
@@ -65,21 +172,77 @@ public function stream_cast($cast_as);
 
   /**
    * Closes stream.
+   *
+   * This method is called in response to fclose(). All resources that were
+   * locked, or allocated, by the wrapper should be released.
+   *
+   * @see fclose()
+   * @see PhpStreamWrapperInterface::dir_closedir()
+   * @see http://php.net/manual/en/streamwrapper.stream-close.php
    */
   public function stream_close();
 
   /**
+   * Tests for end-of-file on a file pointer.
+   *
+   * This method is called in response to feof().
+   *
+   * Warning, when reading the whole file (for example, with
+   * file_get_contents()), PHP will call
+   * PhpStreamWrapperInterface::stream_read() followed by
+   * PhpStreamWrapperInterface::stream_eof() in a loop but as long as
+   * PhpStreamWrapperInterface::stream_read() returns a non-empty string, the
+   * return value of PhpStreamWrapperInterface::stream_eof() is ignored.
+   *
    * @return bool
+   *   Should return TRUE if the read/write position is at the end of the
+   *   stream and if no more data is available to be read, or FALSE otherwise.
+   *
+   * @see feof()
+   * @see http://php.net/manual/en/streamwrapper.stream-eof.php
    */
   public function stream_eof();
 
   /**
+   * Flushes the output.
+   *
+   * This method is called in response to fflush() and when the stream is being
+   * closed while any un-flushed data has been written to it before. If you have
+   * cached data in your stream but not yet stored it into the underlying
+   * storage, you should do so now.
+   *
+   * Note, if not implemented, FALSE is assumed as the return value.
+   *
    * @return bool
+   *   Should return TRUE if the cached data was successfully stored (or if
+   *   there was no data to store), or FALSE if the data could not be stored.
+   *
+   * @see fflush()
+   * @see http://php.net/manual/en/streamwrapper.stream-flush.php
    */
   public function stream_flush();
 
   /**
+   * Advisory file locking.
+   *
+   * This method is called in response to flock(), when file_put_contents()
+   * (when flags contains LOCK_EX), stream_set_blocking() and when closing the
+   * stream (LOCK_UN).
+   *
+   * @param int $operation
+   *   One of:
+   *   - LOCK_SH: To acquire a shared lock (reader).
+   *   - LOCK_EX: To acquire an exclusive lock (writer).
+   *   - LOCK_UN: To release a lock (shared or exclusive).
+   *   - LOCK_NB: If you don't want flock() to block while locking. This
+   *     operation is not supported on Windows.
+   *
    * @return bool
+   *   Returns TRUE on success or FALSE on failure.
+   *
+   * @see flock()
+   * @see stream_set_blocking()
+   * @see http://php.net/manual/en/streamwrapper.stream-lock.php
    */
   public function stream_lock($operation);
 
@@ -116,12 +279,73 @@ public function stream_lock($operation);
   public function stream_metadata($path, $option, $value);
 
   /**
+   * Opens file or URL.
+   *
+   * This method is called immediately after the wrapper is initialized (e.g.
+   * by fopen() and file_get_contents()).
+   *
+   * Note the streamWrapper::$context property is updated if a valid context
+   * is passed to the caller function.
+   *
+   * @param string $path
+   *   Specifies the URL that was passed to the original function. Note that
+   *   the URL can be broken apart with parse_url(). Note that only URLs
+   *   delimited by "://" are supported. ":" and ":/" while technically valid
+   *   URLs, are not.
+   * @param string $mode
+   *   The mode used to open the file, as detailed for fopen(). Note, remember
+   *   to check if the mode is valid for the path requested.
+   * @param int $options
+   *   Holds additional flags set by the streams API. It can hold one or more
+   *   of the following values ORed together:
+   *   - STREAM_USE_PATH: If path is relative, search for the resource using
+   *     the include_path.
+   *   - STREAM_REPORT_ERRORS: If this flag is set, you are responsible for
+   *     raising errors using trigger_error() during opening of the stream. If
+   *     this flag is not set, you should not raise any errors.
+   * @param string $opened_path
+   *   If the path is opened successfully, and STREAM_USE_PATH is set in
+   *   options, opened_path should be set to the full path of the file/resource
+   *   that was actually opened.
+   *
    * @return bool
+   *   Returns TRUE on success or FALSE on failure.
+   *
+   * @see fopen()
+   * @see parse_url()
+   * @see http://php.net/manual/en/streamwrapper.stream-open.php
    */
   public function stream_open($path, $mode, $options, &$opened_path);
 
   /**
-   * @return string
+   * Read from stream.
+   *
+   * This method is called in response to fread() and fgets().
+   *
+   * Note, remember to update the read/write position of the stream (by the
+   * number of bytes that were successfully read).
+   *
+   * Note, PhpStreamWrapperInterface::stream_eof() is called directly after
+   * calling PhpStreamWrapperInterface::stream_read() to check if EOF has been
+   * reached. If not implemented, EOF is assumed.
+   *
+   * Warning, when reading the whole file (e.g., with file_get_contents()), PHP
+   * will call PhpStreamWrapperInterface::stream_read() followed by
+   * PhpStreamWrapperInterface::stream_eof() in a loop but as long as
+   * PhpStreamWrapperInterface::stream_read() returns a non-empty string, the
+   * return value of PhpStreamWrapperInterface::stream_eof() is ignored.
+   *
+   * @param int $count
+   *   How many bytes of data from the current position should be returned.
+   *
+   * @return string|false
+   *   If there are less than $count bytes available, return as many as are
+   *   available. If no more data is available, return either FALSE or an empty
+   *   string.
+   *
+   * @see fread()
+   * @see fgets()
+   * @see http://php.net/manual/en/streamwrapper.stream-read.php
    */
   public function stream_read($count);
 
@@ -183,12 +407,30 @@ public function stream_seek($offset, $whence = SEEK_SET);
   public function stream_set_option($option, $arg1, $arg2);
 
   /**
-   * @return array
+   * Retrieve information about a file resource.
+   *
+   * This method is called in response to fstat().
+   *
+   * @return array|false
+   *   See stat().
+   *
+   * @see stat()
+   * @see PhpStreamWrapperInterface::url_stat()
+   * @see http://php.net/manual/en/streamwrapper.stream-stat.php
    */
   public function stream_stat();
 
   /**
+   * Retrieve the current position of a stream.
+   *
+   * This method is called in response to fseek() to determine the current
+   * position.
+   *
    * @return int
+   *   Should return the current position of the stream.
+   *
+   * @see PhpStreamWrapperInterface::stream_tell()
+   * @see http://php.net/manual/en/streamwrapper.stream-tell.php
    */
   public function stream_tell();
 
@@ -202,21 +444,86 @@ public function stream_tell();
    *
    * @return bool
    *   TRUE on success, FALSE otherwise.
+   *
+   * @see ftruncate()
+   * @see http://php.net/manual/en/streamwrapper.stream-truncate.php
    */
   public function stream_truncate($new_size);
 
   /**
+   * Write to stream.
+   *
+   * This method is called in response to fwrite(). Remember to update the
+   * current position of the stream by number of bytes that were successfully
+   * written.
+   *
+   * @param string $data
+   *   Should be stored into the underlying stream. If there is not enough room
+   *   in the underlying stream, store as much as possible.
+   *
    * @return int
+   *   Should return the number of bytes that were successfully stored, or 0 if
+   *   none could be stored.
+   *
+   * @see fwrite()
+   * @see http://php.net/manual/en/streamwrapper.stream-write.php
    */
   public function stream_write($data);
 
   /**
+   * Delete a file.
+   *
+   * This method is called in response to unlink().
+   *
+   * Note, in order for the appropriate error message to be returned this method
+   * should not be defined if the wrapper does not support removing files.
+   *
+   * Note, the streamWrapper::$context property is updated if a valid context is
+   * passed to the caller function.
+   *
+   * @param string $path
+   *   The file URL which should be deleted.
+   *
    * @return bool
+   *   Returns TRUE on success or FALSE on failure.
+   *
+   * @see unlink()
+   * @see PhpStreamWrapperInterface::rmdir()
+   * @see http://php.net/manual/en/streamwrapper.unlink.php
    */
   public function unlink($path);
 
   /**
-   * @return array
+   * Retrieve information about a file.
+   *
+   * This method is called in response to all stat() related functions.
+   *
+   * Note, the streamWrapper::$context property is updated if a valid context is
+   * passed to the caller function.
+   *
+   * @param string $path
+   *   The file path or URL to stat. Note that in the case of a URL, it must be
+   *   a "://" delimited URL. Other URL forms are not supported.
+   * @param int $flags
+   *   Holds additional flags set by the streams API. It can hold one or more
+   *   of the following values ORed together:
+   *   - STREAM_URL_STAT_LINK: For resources with the ability to link to other
+   *     resource (such as an HTTP Location: forward, or a filesystem symlink).
+   *     This flag specified that only information about the link itself should
+   *     be returned, not the resource pointed to by the link. This flag is set
+   *     in response to calls to lstat(), is_link(), or filetype().
+   *   - STREAM_URL_STAT_QUIET: If this flag is set, your wrapper should not
+   *     raise any errors. If this flag is not set, you are responsible for
+   *     reporting errors using the trigger_error() function during stating of
+   *     the path.
+   *
+   * @return array|false
+   *   Should return the same as stat() does. Unknown or unavailable values
+   *   should be set to a rational value (usually 0).
+   *
+   * @see stat()
+   * @see PhpStreamWrapperInterface::stream_stat()
+   * @see http://php.net/manual/en/streamwrapper.url-stat.php
    */
   public function url_stat($path, $flags);
 
diff --git a/web/core/lib/Drupal/Core/Test/FunctionalTestSetupTrait.php b/web/core/lib/Drupal/Core/Test/FunctionalTestSetupTrait.php
index 2e8594b564..231c4b5d9a 100644
--- a/web/core/lib/Drupal/Core/Test/FunctionalTestSetupTrait.php
+++ b/web/core/lib/Drupal/Core/Test/FunctionalTestSetupTrait.php
@@ -564,7 +564,7 @@ protected function installParameters() {
    * Sets up the base URL based upon the environment variable.
    *
    * @throws \Exception
-   *   Thrown when no SIMPLETEST_BASE_URL environment variable is provided.
+   *   Thrown when no SIMPLETEST_BASE_URL environment variable is provided or uses an invalid scheme.
    */
   protected function setupBaseUrl() {
     global $base_url;
@@ -584,6 +584,13 @@ protected function setupBaseUrl() {
     $path = isset($parsed_url['path']) ? rtrim(rtrim($parsed_url['path']), '/') : '';
     $port = isset($parsed_url['port']) ? $parsed_url['port'] : 80;
 
+    $valid_url_schemes = ['http', 'https'];
+    if (!in_array(strtolower($parsed_url['scheme']), $valid_url_schemes, TRUE)) {
+      throw new \Exception(
+        'You must provide valid scheme for the SIMPLETEST_BASE_URL environment variable. Valid schema are: http, https.'
+      );
+    }
+
     $this->baseUrl = $base_url;
 
     // If the passed URL schema is 'https' then setup the $_SERVER variables
diff --git a/web/core/lib/Drupal/Core/Test/TestDiscovery.php b/web/core/lib/Drupal/Core/Test/TestDiscovery.php
index 879169f61a..b9eeb0db23 100644
--- a/web/core/lib/Drupal/Core/Test/TestDiscovery.php
+++ b/web/core/lib/Drupal/Core/Test/TestDiscovery.php
@@ -186,7 +186,7 @@ public function getTestClasses($extension = NULL, array $types = []) {
       // unavailable modules. TestDiscovery should not filter out module
       // requirements for PHPUnit-based test classes.
       // @todo Move this behavior to \Drupal\simpletest\TestBase so tests can be
-      //       marked as skipped, instead.
+      //   marked as skipped, instead.
       // @see https://www.drupal.org/node/1273478
       if ($info['type'] == 'Simpletest') {
         if (!empty($info['requires']['module'])) {
diff --git a/web/core/lib/Drupal/Core/Validation/DrupalTranslator.php b/web/core/lib/Drupal/Core/Validation/DrupalTranslator.php
index 12b9594c4a..4025feda37 100644
--- a/web/core/lib/Drupal/Core/Validation/DrupalTranslator.php
+++ b/web/core/lib/Drupal/Core/Validation/DrupalTranslator.php
@@ -43,7 +43,7 @@ public function transChoice($id, $number, array $parameters = [], $domain = NULL
     }
 
     // Normally, calls to formatPlural() need to use literal strings, like
-    //   formatPlural($count, '1 item', '@count items')
+    // formatPlural($count, '1 item', '@count items')
     // so that the Drupal project POTX string extractor will correctly
     // extract the strings for translation and save them in a format that
     // formatPlural() can work with. However, this is a special case, because
diff --git a/web/core/modules/action/src/Plugin/migrate/source/Action.php b/web/core/modules/action/src/Plugin/migrate/source/Action.php
index 8a427f566a..6cc1ad157c 100644
--- a/web/core/modules/action/src/Plugin/migrate/source/Action.php
+++ b/web/core/modules/action/src/Plugin/migrate/source/Action.php
@@ -6,7 +6,12 @@
 use Drupal\migrate\Row;
 
 /**
- * Drupal action source from database.
+ * Drupal 6/7 action source from database.
+ *
+ * For available configuration keys, refer to the parent classes.
+ *
+ * @see \Drupal\migrate\Plugin\migrate\source\SqlBase
+ * @see \Drupal\migrate\Plugin\migrate\source\SourcePluginBase
  *
  * @MigrateSource(
  *   id = "action",
diff --git a/web/core/modules/aggregator/src/Plugin/aggregator/processor/DefaultProcessor.php b/web/core/modules/aggregator/src/Plugin/aggregator/processor/DefaultProcessor.php
index 9d19abf1d3..fb229ac801 100644
--- a/web/core/modules/aggregator/src/Plugin/aggregator/processor/DefaultProcessor.php
+++ b/web/core/modules/aggregator/src/Plugin/aggregator/processor/DefaultProcessor.php
@@ -187,7 +187,7 @@ public function process(FeedInterface $feed) {
       return;
     }
     foreach ($feed->items as $item) {
-      // @todo: The default entity view builder always returns an empty
+      // @todo The default entity view builder always returns an empty
       //   array, which is ignored in aggregator_save_item() currently. Should
       //   probably be fixed.
       if (empty($item['title'])) {
diff --git a/web/core/modules/aggregator/src/Plugin/migrate/source/AggregatorFeed.php b/web/core/modules/aggregator/src/Plugin/migrate/source/AggregatorFeed.php
index 7d01536ae9..89a6522560 100644
--- a/web/core/modules/aggregator/src/Plugin/migrate/source/AggregatorFeed.php
+++ b/web/core/modules/aggregator/src/Plugin/migrate/source/AggregatorFeed.php
@@ -5,7 +5,12 @@
 use Drupal\migrate_drupal\Plugin\migrate\source\DrupalSqlBase;
 
 /**
- * Drupal feed source from database.
+ * Drupal 6/7 feed source from database.
+ *
+ * For available configuration keys, refer to the parent classes.
+ *
+ * @see \Drupal\migrate\Plugin\migrate\source\SqlBase
+ * @see \Drupal\migrate\Plugin\migrate\source\SourcePluginBase
  *
  * @MigrateSource(
  *   id = "aggregator_feed",
diff --git a/web/core/modules/aggregator/src/Plugin/migrate/source/AggregatorItem.php b/web/core/modules/aggregator/src/Plugin/migrate/source/AggregatorItem.php
index 8cde1f83d1..11fc9575f9 100644
--- a/web/core/modules/aggregator/src/Plugin/migrate/source/AggregatorItem.php
+++ b/web/core/modules/aggregator/src/Plugin/migrate/source/AggregatorItem.php
@@ -5,7 +5,12 @@
 use Drupal\migrate_drupal\Plugin\migrate\source\DrupalSqlBase;
 
 /**
- * Drupal aggregator item source from database.
+ * Drupal 6/7 aggregator item source from database.
+ *
+ * For available configuration keys, refer to the parent classes.
+ *
+ * @see \Drupal\migrate\Plugin\migrate\source\SqlBase
+ * @see \Drupal\migrate\Plugin\migrate\source\SourcePluginBase
  *
  * @MigrateSource(
  *   id = "aggregator_item",
diff --git a/web/core/modules/aggregator/tests/src/Kernel/Migrate/d7/MigrateAggregatorItemTest.php b/web/core/modules/aggregator/tests/src/Kernel/Migrate/d7/MigrateAggregatorItemTest.php
index 2780507a97..c977b77279 100644
--- a/web/core/modules/aggregator/tests/src/Kernel/Migrate/d7/MigrateAggregatorItemTest.php
+++ b/web/core/modules/aggregator/tests/src/Kernel/Migrate/d7/MigrateAggregatorItemTest.php
@@ -45,7 +45,7 @@ public function testAggregatorItem() {
       $this->assertSame($original->fid, $item->getFeedId());
       $this->assertSame($original->title, $item->label());
       // If $original->author is an empty string, getAuthor() returns NULL so
-      // we need to use assertEqual() here.
+      // we need to use assertEquals() here.
       $this->assertEquals($original->author, $item->getAuthor());
       $this->assertSame($original->description, $item->getDescription());
       $this->assertSame($original->link, $item->getLink());
diff --git a/web/core/modules/aggregator/tests/src/Unit/Plugin/AggregatorPluginSettingsBaseTest.php b/web/core/modules/aggregator/tests/src/Unit/Plugin/AggregatorPluginSettingsBaseTest.php
index 0b2da48d46..c1340d0d94 100644
--- a/web/core/modules/aggregator/tests/src/Unit/Plugin/AggregatorPluginSettingsBaseTest.php
+++ b/web/core/modules/aggregator/tests/src/Unit/Plugin/AggregatorPluginSettingsBaseTest.php
@@ -87,14 +87,14 @@ public function testSettingsForm() {
       ->setMethods(['buildConfigurationForm', 'validateConfigurationForm', 'submitConfigurationForm'])
       ->setConstructorArgs([[], 'aggregator_test', ['description' => ''], $this->configFactory])
       ->getMock();
-    $test_processor->expects($this->at(0))
+    $test_processor->expects($this->once())
       ->method('buildConfigurationForm')
       ->with($this->anything(), $form_state)
       ->will($this->returnArgument(0));
-    $test_processor->expects($this->at(1))
+    $test_processor->expects($this->once())
       ->method('validateConfigurationForm')
       ->with($this->anything(), $form_state);
-    $test_processor->expects($this->at(2))
+    $test_processor->expects($this->once())
       ->method('submitConfigurationForm')
       ->with($this->anything(), $form_state);
 
diff --git a/web/core/modules/ban/src/Plugin/migrate/source/d7/BlockedIps.php b/web/core/modules/ban/src/Plugin/migrate/source/d7/BlockedIps.php
index 7d3eeebba2..c1173af4b2 100644
--- a/web/core/modules/ban/src/Plugin/migrate/source/d7/BlockedIps.php
+++ b/web/core/modules/ban/src/Plugin/migrate/source/d7/BlockedIps.php
@@ -5,7 +5,12 @@
 use Drupal\migrate_drupal\Plugin\migrate\source\DrupalSqlBase;
 
 /**
- * Drupal 7 blocked IPs from database.
+ * Drupal 7 blocked IPs source from database.
+ *
+ * For available configuration keys, refer to the parent classes.
+ *
+ * @see \Drupal\migrate\Plugin\migrate\source\SqlBase
+ * @see \Drupal\migrate\Plugin\migrate\source\SourcePluginBase
  *
  * @MigrateSource(
  *   id = "d7_blocked_ips",
diff --git a/web/core/modules/big_pipe/tests/src/Functional/BigPipeTest.php b/web/core/modules/big_pipe/tests/src/Functional/BigPipeTest.php
index 63436ef793..61d2acd8f7 100644
--- a/web/core/modules/big_pipe/tests/src/Functional/BigPipeTest.php
+++ b/web/core/modules/big_pipe/tests/src/Functional/BigPipeTest.php
@@ -389,7 +389,7 @@ protected function assertBigPipePlaceholders(array $expected_big_pipe_placeholde
     $placeholders = array_map(function (NodeElement $element) {
       return $element->getAttribute('data-big-pipe-placeholder-id');
     }, $this->cssSelect('[data-big-pipe-placeholder-id]'));
-    $this->assertSame(count($expected_big_pipe_placeholders), count(array_unique($placeholders)));
+    $this->assertSameSize($expected_big_pipe_placeholders, array_unique($placeholders));
     $expected_big_pipe_placeholders_with_replacements = [];
     foreach ($expected_big_pipe_placeholder_stream_order as $big_pipe_placeholder_id) {
       $expected_big_pipe_placeholders_with_replacements[$big_pipe_placeholder_id] = $expected_big_pipe_placeholders[$big_pipe_placeholder_id];
diff --git a/web/core/modules/block/tests/src/FunctionalJavascript/BlockFilterTest.php b/web/core/modules/block/tests/src/FunctionalJavascript/BlockFilterTest.php
index c5a8052914..4b7983f2d4 100644
--- a/web/core/modules/block/tests/src/FunctionalJavascript/BlockFilterTest.php
+++ b/web/core/modules/block/tests/src/FunctionalJavascript/BlockFilterTest.php
@@ -56,7 +56,7 @@ public function testBlockFilter() {
     $session->wait(10000, 'jQuery("#drupal-live-announce").html().indexOf("blocks are available") > -1');
     $visible_rows = $this->filterVisibleElements($block_rows);
     if (count($block_rows) > 0) {
-      $this->assertNotEquals(count($block_rows), count($visible_rows));
+      $this->assertNotSameSize($block_rows, $visible_rows);
     }
 
     // Test Drupal.announce() message when multiple matches are expected.
diff --git a/web/core/modules/block/tests/src/Kernel/NewDefaultThemeBlocksTest.php b/web/core/modules/block/tests/src/Kernel/NewDefaultThemeBlocksTest.php
index d027a6f14e..70e34e6227 100644
--- a/web/core/modules/block/tests/src/Kernel/NewDefaultThemeBlocksTest.php
+++ b/web/core/modules/block/tests/src/Kernel/NewDefaultThemeBlocksTest.php
@@ -63,7 +63,7 @@ public function testNewDefaultThemeBlocks() {
     $new_blocks = $block_storage->getQuery()
       ->condition('theme', $new_theme)
       ->execute();
-    $this->assertSame(count($default_block_names), count($new_blocks));
+    $this->assertSameSize($default_block_names, $new_blocks);
 
     foreach ($default_block_names as $default_block_name) {
       // Remove the matching block from the list of blocks in the new theme.
diff --git a/web/core/modules/book/src/Plugin/migrate/source/Book.php b/web/core/modules/book/src/Plugin/migrate/source/Book.php
index b9748708fb..e382f03d78 100644
--- a/web/core/modules/book/src/Plugin/migrate/source/Book.php
+++ b/web/core/modules/book/src/Plugin/migrate/source/Book.php
@@ -5,7 +5,12 @@
 use Drupal\migrate_drupal\Plugin\migrate\source\DrupalSqlBase;
 
 /**
- * Drupal 6 and 7 book source.
+ * Drupal 6/7 book source from database.
+ *
+ * For available configuration keys, refer to the parent classes.
+ *
+ * @see \Drupal\migrate\Plugin\migrate\source\SqlBase
+ * @see \Drupal\migrate\Plugin\migrate\source\SourcePluginBase
  *
  * @MigrateSource(
  *   id = "book",
diff --git a/web/core/modules/book/tests/src/Functional/BookTest.php b/web/core/modules/book/tests/src/Functional/BookTest.php
index d52434125b..1513675876 100644
--- a/web/core/modules/book/tests/src/Functional/BookTest.php
+++ b/web/core/modules/book/tests/src/Functional/BookTest.php
@@ -637,7 +637,7 @@ public function testAdminBookNodeListing() {
 
     $elements = $this->xpath('//table//ul[@class="dropbutton"]/li/a');
     $this->assertEquals('View', $elements[0]->getText(), 'View link is found from the list.');
-    $this->assertEquals(count($nodes), count($elements), 'All the book pages are displayed on the book outline page.');
+    $this->assertSameSize($nodes, $elements, 'All the book pages are displayed on the book outline page.');
 
     // Unpublish a book in the hierarchy.
     $nodes[0]->setUnPublished();
@@ -646,7 +646,7 @@ public function testAdminBookNodeListing() {
     // Node should still appear on the outline for admins.
     $this->drupalGet('admin/structure/book/' . $this->book->id());
     $elements = $this->xpath('//table//ul[@class="dropbutton"]/li/a');
-    $this->assertEquals(count($nodes), count($elements), 'All the book pages are displayed on the book outline page.');
+    $this->assertSameSize($nodes, $elements, 'All the book pages are displayed on the book outline page.');
 
     // Saving a book page not as the current version shouldn't effect the book.
     $old_title = $nodes[1]->getTitle();
@@ -657,7 +657,7 @@ public function testAdminBookNodeListing() {
     $nodes[1]->save();
     $this->drupalGet('admin/structure/book/' . $this->book->id());
     $elements = $this->xpath('//table//ul[@class="dropbutton"]/li/a');
-    $this->assertEquals(count($nodes), count($elements), 'All the book pages are displayed on the book outline page.');
+    $this->assertSameSize($nodes, $elements, 'All the book pages are displayed on the book outline page.');
     $this->assertSession()->responseNotContains($new_title);
     $this->assertSession()->responseContains($old_title);
   }
diff --git a/web/core/modules/book/tests/src/FunctionalJavascript/BookJavascriptTest.php b/web/core/modules/book/tests/src/FunctionalJavascript/BookJavascriptTest.php
index 1c8616dcf1..cb4ac799b4 100644
--- a/web/core/modules/book/tests/src/FunctionalJavascript/BookJavascriptTest.php
+++ b/web/core/modules/book/tests/src/FunctionalJavascript/BookJavascriptTest.php
@@ -70,7 +70,7 @@ public function testBookOrdering() {
     $this->assertSession()->pageTextNotContains('You have unsaved changes.');
 
     // Drag and drop the '1st page' row over the '2nd page' row.
-    // @todo: Test also the reverse, '2nd page' over '1st page', when
+    // @todo Test also the reverse, '2nd page' over '1st page', when
     //   https://www.drupal.org/node/2769825 is fixed.
     // @see https://www.drupal.org/node/2769825
     $dragged = $this->xpath("//tr[@data-drupal-selector='edit-table-book-admin-{$page1->id()}']//a[@class='tabledrag-handle']")[0];
diff --git a/web/core/modules/ckeditor/src/Plugin/CKEditorPlugin/Internal.php b/web/core/modules/ckeditor/src/Plugin/CKEditorPlugin/Internal.php
index cd33f51514..8b4dbe0980 100644
--- a/web/core/modules/ckeditor/src/Plugin/CKEditorPlugin/Internal.php
+++ b/web/core/modules/ckeditor/src/Plugin/CKEditorPlugin/Internal.php
@@ -475,8 +475,8 @@ protected function generateACFSettings(Editor $editor) {
           // attributes is allowed. However, that may not be the case: the "*"
           // tag may still apply restrictions.
           // Since CKEditor's ACF follows the following principle:
-          //     Once validated, an element or its property cannot be
-          //     invalidated by another rule.
+          // - Once validated, an element or its property cannot be
+          //   invalidated by another rule.
           // That means that the most permissive setting wins. Which means that
           // it will still be allowed by CKEditor, for instance, to define any
           // style, no matter what the "*" tag's restrictions may be. If there
diff --git a/web/core/modules/ckeditor/tests/src/Kernel/CKEditorPluginManagerTest.php b/web/core/modules/ckeditor/tests/src/Kernel/CKEditorPluginManagerTest.php
index e8d49c46f0..32f1c77c8f 100644
--- a/web/core/modules/ckeditor/tests/src/Kernel/CKEditorPluginManagerTest.php
+++ b/web/core/modules/ckeditor/tests/src/Kernel/CKEditorPluginManagerTest.php
@@ -86,13 +86,13 @@ public function testEnabledPlugins() {
     $this->assertSame(['internal' => NULL] + $enabled_plugins, $this->manager->getEnabledPluginFiles($editor, TRUE), 'Only the "internal" plugin is enabled.');
 
     // Case 3: enable each of the newly available plugins, if possible:
-    // a. Llama: cannot be enabled, since it does not implement
+    // 1. Llama: cannot be enabled, since it does not implement
     //    CKEditorPluginContextualInterface nor CKEditorPluginButtonsInterface.
-    // b. LlamaContextual: enabled by adding the 'Strike' button, which is
+    // 2. LlamaContextual: enabled by adding the 'Strike' button, which is
     //    part of another plugin!
-    // c. LlamaButton: automatically enabled by adding its 'Llama' button.
-    // d. LlamaContextualAndButton: enabled by either b or c.
-    // e. LlamaCSS: automatically enabled by add its 'LlamaCSS' button.
+    // 3. LlamaButton: automatically enabled by adding its 'Llama' button.
+    // 4. LlamaContextualAndButton: enabled by either 2 or 3.
+    // 5. LlamaCSS: automatically enabled by add its 'LlamaCSS' button.
     // Below, we will first enable the "Llama" button, which will cause the
     // LlamaButton and LlamaContextualAndButton plugins to be enabled. Then we
     // will remove the "Llama" button and add the "Strike" button, which will
diff --git a/web/core/modules/ckeditor/tests/src/Unit/Plugin/CKEditorPlugin/LanguageTest.php b/web/core/modules/ckeditor/tests/src/Unit/Plugin/CKEditorPlugin/LanguageTest.php
index dd87199ed1..1c6b56bb12 100644
--- a/web/core/modules/ckeditor/tests/src/Unit/Plugin/CKEditorPlugin/LanguageTest.php
+++ b/web/core/modules/ckeditor/tests/src/Unit/Plugin/CKEditorPlugin/LanguageTest.php
@@ -32,8 +32,8 @@ public function setUp(): void {
    */
   public function providerGetConfig() {
     return [
-      ['un', count(LanguageManager::getUnitedNationsLanguageList())],
-      ['all', count(LanguageManager::getStandardLanguageList())],
+      ['un', LanguageManager::getUnitedNationsLanguageList()],
+      ['all', LanguageManager::getStandardLanguageList()],
     ];
   }
 
@@ -42,7 +42,7 @@ public function providerGetConfig() {
    *
    * @dataProvider providerGetConfig
    */
-  public function testGetConfig($language_list, $expected_number) {
+  public function testGetConfig($language_list, $expected_languages) {
     $editor = $this->getMockBuilder('Drupal\editor\Entity\Editor')
       ->disableOriginalConstructor()
       ->getMock();
@@ -59,7 +59,7 @@ public function testGetConfig($language_list, $expected_number) {
     $this->assertContains('fr:French', $config['language_list']);
     $this->assertContains('ru:Russian', $config['language_list']);
     $this->assertContains('ar:Arabic:rtl', $config['language_list']);
-    $this->assertEquals($expected_number, count($config['language_list']));
+    $this->assertSameSize($expected_languages, $config['language_list']);
   }
 
 }
diff --git a/web/core/modules/color/src/Plugin/migrate/source/d7/Color.php b/web/core/modules/color/src/Plugin/migrate/source/d7/Color.php
index d0382c2f0e..7ae8edcd47 100644
--- a/web/core/modules/color/src/Plugin/migrate/source/d7/Color.php
+++ b/web/core/modules/color/src/Plugin/migrate/source/d7/Color.php
@@ -13,6 +13,11 @@
 /**
  * Drupal 7 color source from database.
  *
+ * For available configuration keys, refer to the parent classes.
+ *
+ * @see \Drupal\migrate\Plugin\migrate\source\SqlBase
+ * @see \Drupal\migrate\Plugin\migrate\source\SourcePluginBase
+ *
  * @MigrateSource(
  *   id = "d7_color",
  *   source_module = "color"
diff --git a/web/core/modules/comment/src/Plugin/migrate/source/CommentType.php b/web/core/modules/comment/src/Plugin/migrate/source/CommentType.php
index 860635255b..9ab3d8f4a3 100644
--- a/web/core/modules/comment/src/Plugin/migrate/source/CommentType.php
+++ b/web/core/modules/comment/src/Plugin/migrate/source/CommentType.php
@@ -7,7 +7,12 @@
 use Drupal\migrate_drupal\Plugin\migrate\source\DrupalSqlBase;
 
 /**
- * Migration source for Drupal 6 and Drupal 7 comment types.
+ * Drupal 6/7 comment types source from database.
+ *
+ * For available configuration keys, refer to the parent classes.
+ *
+ * @see \Drupal\migrate\Plugin\migrate\source\SqlBase
+ * @see \Drupal\migrate\Plugin\migrate\source\SourcePluginBase
  *
  * @MigrateSource(
  *   id = "comment_type",
diff --git a/web/core/modules/comment/src/Plugin/migrate/source/d6/Comment.php b/web/core/modules/comment/src/Plugin/migrate/source/d6/Comment.php
index a1fa58f34e..fb702a9dd3 100644
--- a/web/core/modules/comment/src/Plugin/migrate/source/d6/Comment.php
+++ b/web/core/modules/comment/src/Plugin/migrate/source/d6/Comment.php
@@ -8,6 +8,11 @@
 /**
  * Drupal 6 comment source from database.
  *
+ * For available configuration keys, refer to the parent classes.
+ *
+ * @see \Drupal\migrate\Plugin\migrate\source\SqlBase
+ * @see \Drupal\migrate\Plugin\migrate\source\SourcePluginBase
+ *
  * @MigrateSource(
  *   id = "d6_comment",
  *   source_module = "comment"
diff --git a/web/core/modules/comment/src/Plugin/migrate/source/d7/Comment.php b/web/core/modules/comment/src/Plugin/migrate/source/d7/Comment.php
index c371acc045..54a3efb293 100644
--- a/web/core/modules/comment/src/Plugin/migrate/source/d7/Comment.php
+++ b/web/core/modules/comment/src/Plugin/migrate/source/d7/Comment.php
@@ -8,6 +8,11 @@
 /**
  * Drupal 7 comment source from database.
  *
+ * For available configuration keys, refer to the parent classes.
+ *
+ * @see \Drupal\migrate\Plugin\migrate\source\SqlBase
+ * @see \Drupal\migrate\Plugin\migrate\source\SourcePluginBase
+ *
  * @MigrateSource(
  *   id = "d7_comment",
  *   source_module = "comment"
diff --git a/web/core/modules/comment/src/Plugin/migrate/source/d7/CommentEntityTranslation.php b/web/core/modules/comment/src/Plugin/migrate/source/d7/CommentEntityTranslation.php
index efdec81974..e14560fe0c 100644
--- a/web/core/modules/comment/src/Plugin/migrate/source/d7/CommentEntityTranslation.php
+++ b/web/core/modules/comment/src/Plugin/migrate/source/d7/CommentEntityTranslation.php
@@ -7,7 +7,12 @@
 use Drupal\migrate_drupal\Plugin\migrate\source\d7\FieldableEntity;
 
 /**
- * Provides Drupal 7 comment entity translation source plugin.
+ * Drupal 7 comment entity translation source plugin.
+ *
+ * For available configuration keys, refer to the parent classes.
+ *
+ * @see \Drupal\migrate\Plugin\migrate\source\SqlBase
+ * @see \Drupal\migrate\Plugin\migrate\source\SourcePluginBase
  *
  * @MigrateSource(
  *   id = "d7_comment_entity_translation",
diff --git a/web/core/modules/comment/tests/src/Functional/CommentThreadingTest.php b/web/core/modules/comment/tests/src/Functional/CommentThreadingTest.php
index aaab0e617f..00ccd29c24 100644
--- a/web/core/modules/comment/tests/src/Functional/CommentThreadingTest.php
+++ b/web/core/modules/comment/tests/src/Functional/CommentThreadingTest.php
@@ -134,12 +134,14 @@ public function testCommentThreading() {
    */
   protected function assertParentLink($cid, $pid) {
     // This pattern matches a markup structure like:
+    // @code
     // <a id="comment-2"></a>
     // <article>
     //   <p class="parent">
     //     <a href="...comment-1"></a>
     //   </p>
-    //  </article>
+    // </article>
+    // @endcode
     $pattern = "//article[@id='comment-$cid']//p[contains(@class, 'parent')]//a[contains(@href, 'comment-$pid')]";
 
     $this->assertSession()->elementExists('xpath', $pattern);
@@ -153,10 +155,12 @@ protected function assertParentLink($cid, $pid) {
    */
   protected function assertNoParentLink($cid) {
     // This pattern matches a markup structure like:
+    // @code
     // <a id="comment-2"></a>
     // <article>
     //   <p class="parent"></p>
-    //  </article>
+    // </article>
+    // @endcode
 
     $pattern = "//article[@id='comment-$cid']//p[contains(@class, 'parent')]";
     $this->assertSession()->elementNotExists('xpath', $pattern);
diff --git a/web/core/modules/comment/tests/src/Kernel/Migrate/d6/MigrateCommentTypeTest.php b/web/core/modules/comment/tests/src/Kernel/Migrate/d6/MigrateCommentTypeTest.php
index a9c086aa2e..359116b882 100644
--- a/web/core/modules/comment/tests/src/Kernel/Migrate/d6/MigrateCommentTypeTest.php
+++ b/web/core/modules/comment/tests/src/Kernel/Migrate/d6/MigrateCommentTypeTest.php
@@ -93,7 +93,7 @@ public function testNoCommentTypeMigration(array $disabled_source_modules, array
     ];
 
     foreach ($expected_messages as $type => $expected_messages_by_type) {
-      $this->assertEquals(count($expected_messages_by_type), count($actual_messages[$type]));
+      $this->assertSameSize($expected_messages_by_type, $actual_messages[$type]);
       // Cast the actual messages to string.
       $actual_messages_by_type = array_reduce($actual_messages[$type], function (array $carry, $actual_message) {
         $carry[] = (string) $actual_message;
diff --git a/web/core/modules/comment/tests/src/Kernel/Migrate/d7/MigrateCommentTypeTest.php b/web/core/modules/comment/tests/src/Kernel/Migrate/d7/MigrateCommentTypeTest.php
index 7e7f1b4505..0da71b7b14 100644
--- a/web/core/modules/comment/tests/src/Kernel/Migrate/d7/MigrateCommentTypeTest.php
+++ b/web/core/modules/comment/tests/src/Kernel/Migrate/d7/MigrateCommentTypeTest.php
@@ -99,7 +99,7 @@ public function testNoCommentTypeMigration(array $disabled_source_modules, array
     ];
 
     foreach ($expected_messages as $type => $expected_messages_by_type) {
-      $this->assertEquals(count($expected_messages_by_type), count($actual_messages[$type]));
+      $this->assertSameSize($expected_messages_by_type, $actual_messages[$type]);
       // Cast the actual messages to string.
       $actual_messages_by_type = array_reduce($actual_messages[$type], function (array $carry, $actual_message) {
         $carry[] = (string) $actual_message;
diff --git a/web/core/modules/comment/tests/src/Unit/CommentStatisticsUnitTest.php b/web/core/modules/comment/tests/src/Unit/CommentStatisticsUnitTest.php
index 068d77bb41..f24f456ced 100644
--- a/web/core/modules/comment/tests/src/Unit/CommentStatisticsUnitTest.php
+++ b/web/core/modules/comment/tests/src/Unit/CommentStatisticsUnitTest.php
@@ -97,7 +97,7 @@ protected function setUp(): void {
   public function testRead() {
     $this->calls_to_fetch = 0;
     $results = $this->commentStatistics->read(['1' => 'boo', '2' => 'foo'], 'snafus');
-    $this->assertEquals($results, ['something', 'something-else']);
+    $this->assertEquals(['something', 'something-else'], $results);
   }
 
   /**
diff --git a/web/core/modules/comment/tests/src/Unit/Entity/CommentLockTest.php b/web/core/modules/comment/tests/src/Unit/Entity/CommentLockTest.php
index c9c8cb3351..786c8e3dbb 100644
--- a/web/core/modules/comment/tests/src/Unit/Entity/CommentLockTest.php
+++ b/web/core/modules/comment/tests/src/Unit/Entity/CommentLockTest.php
@@ -30,11 +30,11 @@ public function testLocks() {
     $lock = $this->createMock('Drupal\Core\Lock\LockBackendInterface');
     $cid = 2;
     $lock_name = "comment:$cid:.00/";
-    $lock->expects($this->at(0))
+    $lock->expects($this->once())
       ->method('acquire')
       ->with($lock_name, 30)
       ->will($this->returnValue(TRUE));
-    $lock->expects($this->at(1))
+    $lock->expects($this->once())
       ->method('release')
       ->with($lock_name);
     $lock->expects($this->exactly(2))
diff --git a/web/core/modules/contact/src/Plugin/migrate/source/ContactCategory.php b/web/core/modules/contact/src/Plugin/migrate/source/ContactCategory.php
index c361588efc..d882c2ad73 100644
--- a/web/core/modules/contact/src/Plugin/migrate/source/ContactCategory.php
+++ b/web/core/modules/contact/src/Plugin/migrate/source/ContactCategory.php
@@ -6,7 +6,12 @@
 use Drupal\migrate_drupal\Plugin\migrate\source\DrupalSqlBase;
 
 /**
- * Contact category source from database.
+ * Drupal 6/7 contact category source from database.
+ *
+ * For available configuration keys, refer to the parent classes.
+ *
+ * @see \Drupal\migrate\Plugin\migrate\source\SqlBase
+ * @see \Drupal\migrate\Plugin\migrate\source\SourcePluginBase
  *
  * @MigrateSource(
  *   id = "contact_category",
diff --git a/web/core/modules/contact/src/Plugin/migrate/source/ContactSettings.php b/web/core/modules/contact/src/Plugin/migrate/source/ContactSettings.php
index 8297be6ae9..9b735bd465 100644
--- a/web/core/modules/contact/src/Plugin/migrate/source/ContactSettings.php
+++ b/web/core/modules/contact/src/Plugin/migrate/source/ContactSettings.php
@@ -5,6 +5,13 @@
 use Drupal\migrate_drupal\Plugin\migrate\source\Variable;
 
 /**
+ * Drupal 6/7 contact settings source from database.
+ *
+ * For available configuration keys, refer to the parent classes.
+ *
+ * @see \Drupal\migrate\Plugin\migrate\source\SqlBase
+ * @see \Drupal\migrate\Plugin\migrate\source\SourcePluginBase
+ *
  * @MigrateSource(
  *   id = "contact_settings",
  *   source_module = "contact"
diff --git a/web/core/modules/content_moderation/tests/src/Kernel/EntityStateChangeValidationTest.php b/web/core/modules/content_moderation/tests/src/Kernel/EntityStateChangeValidationTest.php
index 44abf94d90..606ffee101 100644
--- a/web/core/modules/content_moderation/tests/src/Kernel/EntityStateChangeValidationTest.php
+++ b/web/core/modules/content_moderation/tests/src/Kernel/EntityStateChangeValidationTest.php
@@ -348,7 +348,7 @@ public function testTransitionAccessValidation($permissions, $target_state, $mes
     ]);
     $this->assertTrue($node->isNew());
     $violations = $node->validate();
-    $this->assertCount(count($messages), $violations);
+    $this->assertSameSize($messages, $violations);
     foreach ($messages as $i => $message) {
       $this->assertEquals($message, $violations->get($i)->getMessage());
     }
diff --git a/web/core/modules/content_translation/src/Plugin/migrate/source/d7/EntityTranslationSettings.php b/web/core/modules/content_translation/src/Plugin/migrate/source/d7/EntityTranslationSettings.php
index f35a205ae4..f01146159f 100644
--- a/web/core/modules/content_translation/src/Plugin/migrate/source/d7/EntityTranslationSettings.php
+++ b/web/core/modules/content_translation/src/Plugin/migrate/source/d7/EntityTranslationSettings.php
@@ -5,7 +5,12 @@
 use Drupal\migrate_drupal\Plugin\migrate\source\DrupalSqlBase;
 
 /**
- * Drupal 7 Entity Translation settings from variables.
+ * Drupal 7 Entity Translation settings (variables) from database.
+ *
+ * For available configuration keys, refer to the parent classes.
+ *
+ * @see \Drupal\migrate\Plugin\migrate\source\SqlBase
+ * @see \Drupal\migrate\Plugin\migrate\source\SourcePluginBase
  *
  * @MigrateSource(
  *   id = "d7_entity_translation_settings",
diff --git a/web/core/modules/content_translation/tests/src/Functional/ContentTranslationUITestBase.php b/web/core/modules/content_translation/tests/src/Functional/ContentTranslationUITestBase.php
index f0d624dc3f..ea90c595f5 100644
--- a/web/core/modules/content_translation/tests/src/Functional/ContentTranslationUITestBase.php
+++ b/web/core/modules/content_translation/tests/src/Functional/ContentTranslationUITestBase.php
@@ -590,10 +590,10 @@ protected function doTestTranslationChanged() {
       }
 
       if ($translatable_changed_field) {
-        $this->assertEquals(count($entity->getTranslationLanguages()), count($timestamps), 'All timestamps from all languages are different.');
+        $this->assertSameSize($entity->getTranslationLanguages(), $timestamps, 'All timestamps from all languages are different.');
       }
       else {
-        $this->assertEquals(1, count($timestamps), 'All timestamps from all languages are identical.');
+        $this->assertCount(1, $timestamps, 'All timestamps from all languages are identical.');
       }
     }
   }
diff --git a/web/core/modules/content_translation/tests/src/Unit/Access/ContentTranslationManageAccessCheckTest.php b/web/core/modules/content_translation/tests/src/Unit/Access/ContentTranslationManageAccessCheckTest.php
index 8a6333522b..4e585c9a51 100644
--- a/web/core/modules/content_translation/tests/src/Unit/Access/ContentTranslationManageAccessCheckTest.php
+++ b/web/core/modules/content_translation/tests/src/Unit/Access/ContentTranslationManageAccessCheckTest.php
@@ -67,21 +67,15 @@ public function testCreateAccess() {
 
     // Set the mock language manager.
     $language_manager = $this->createMock('Drupal\Core\Language\LanguageManagerInterface');
-    $language_manager->expects($this->at(0))
-      ->method('getLanguage')
-      ->with($this->equalTo($source))
-      ->will($this->returnValue(new Language(['id' => 'en'])));
-    $language_manager->expects($this->at(1))
+    $language_manager->expects($this->once())
       ->method('getLanguages')
-      ->will($this->returnValue(['en' => [], 'it' => []]));
-    $language_manager->expects($this->at(2))
-      ->method('getLanguage')
-      ->with($this->equalTo($source))
-      ->will($this->returnValue(new Language(['id' => 'en'])));
-    $language_manager->expects($this->at(3))
+      ->willReturn([$source => [], $target => []]);
+    $language_manager->expects($this->any())
       ->method('getLanguage')
-      ->with($this->equalTo($target))
-      ->will($this->returnValue(new Language(['id' => 'it'])));
+      ->willReturnMap([
+        [$source, new Language(['id' => $source])],
+        [$target, new Language(['id' => $target])],
+      ]);
 
     // Set the mock entity. We need to use ContentEntityBase for mocking due to
     // issues with phpunit and multiple interfaces.
diff --git a/web/core/modules/dblog/tests/src/Functional/DbLogTest.php b/web/core/modules/dblog/tests/src/Functional/DbLogTest.php
index 33550b37f8..9853314eeb 100644
--- a/web/core/modules/dblog/tests/src/Functional/DbLogTest.php
+++ b/web/core/modules/dblog/tests/src/Functional/DbLogTest.php
@@ -876,9 +876,9 @@ public function testSameTimestampEntries() {
     $this->drupalGet('admin/reports/dblog');
 
     $entries = $this->getLogEntries();
-    $this->assertEquals($entries[0]['message'], 'Third Entry #0');
-    $this->assertEquals($entries[1]['message'], 'Second Entry #0');
-    $this->assertEquals($entries[2]['message'], 'First Entry #0');
+    $this->assertEquals('Third Entry #0', $entries[0]['message']);
+    $this->assertEquals('Second Entry #0', $entries[1]['message']);
+    $this->assertEquals('First Entry #0', $entries[2]['message']);
   }
 
   /**
diff --git a/web/core/modules/editor/tests/src/Functional/EditorSecurityTest.php b/web/core/modules/editor/tests/src/Functional/EditorSecurityTest.php
index 1cb2724e4f..4574ccb5ae 100644
--- a/web/core/modules/editor/tests/src/Functional/EditorSecurityTest.php
+++ b/web/core/modules/editor/tests/src/Functional/EditorSecurityTest.php
@@ -80,11 +80,11 @@ protected function setUp(): void {
     parent::setUp();
 
     // Create 5 text formats, to cover all potential use cases:
-    //  1. restricted_without_editor (untrusted: anonymous)
-    //  2. restricted_with_editor (normal: authenticated)
-    //  3. restricted_plus_dangerous_tag_with_editor (privileged: trusted)
-    //  4. unrestricted_without_editor (privileged: admin)
-    //  5. unrestricted_with_editor (privileged: admin)
+    // 1. restricted_without_editor (untrusted: anonymous)
+    // 2. restricted_with_editor (normal: authenticated)
+    // 3. restricted_plus_dangerous_tag_with_editor (privileged: trusted)
+    // 4. unrestricted_without_editor (privileged: admin)
+    // 5. unrestricted_with_editor (privileged: admin)
     // With text formats 2, 3 and 5, we also associate a text editor that does
     // not guarantee XSS safety. "restricted" means the text format has XSS
     // filters on output, "unrestricted" means the opposite.
@@ -170,12 +170,12 @@ protected function setUp(): void {
     ]);
 
     // Create 4 users, each with access to different text formats/editors:
-    //   - "untrusted": restricted_without_editor
-    //   - "normal": restricted_with_editor,
-    //   - "trusted": restricted_plus_dangerous_tag_with_editor
-    //   - "privileged": restricted_without_editor, restricted_with_editor,
-    //     restricted_plus_dangerous_tag_with_editor,
-    //     unrestricted_without_editor and unrestricted_with_editor
+    // - "untrusted": restricted_without_editor
+    // - "normal": restricted_with_editor,
+    // - "trusted": restricted_plus_dangerous_tag_with_editor
+    // - "privileged": restricted_without_editor, restricted_with_editor,
+    //   restricted_plus_dangerous_tag_with_editor,
+    //   unrestricted_without_editor and unrestricted_with_editor
     $this->untrustedUser = $this->drupalCreateUser([
       'create article content',
       'edit any article content',
@@ -387,8 +387,8 @@ public function testSwitchingSecurity() {
     ];
 
     // Log in as the privileged user, and for every sample, do the following:
-    //  - switch to every other text format/editor
-    //  - assert the XSS-filtered values that we get from the server
+    // - switch to every other text format/editor
+    // - assert the XSS-filtered values that we get from the server
     $this->drupalLogin($this->privilegedUser);
     $cookies = $this->getSessionCookies();
 
diff --git a/web/core/modules/editor/tests/src/Unit/EditorXssFilter/StandardTest.php b/web/core/modules/editor/tests/src/Unit/EditorXssFilter/StandardTest.php
index 59ea5446fb..b570982ab5 100644
--- a/web/core/modules/editor/tests/src/Unit/EditorXssFilter/StandardTest.php
+++ b/web/core/modules/editor/tests/src/Unit/EditorXssFilter/StandardTest.php
@@ -144,7 +144,7 @@ public function providerTestFilterXss() {
 
     // Spaces and meta chars before the JavaScript in images for XSS.
     // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#Spaces_and_meta_chars_before_the_JavaScript_in_images_for_XSS
-    // @fixme This dataset currently fails under 5.4 because of
+    // @todo This dataset currently fails under 5.4 because of
     //   https://www.drupal.org/node/1210798. Restore after it's fixed.
     if (version_compare(PHP_VERSION, '5.4.0', '<')) {
       $data[] = ['<IMG SRC=" &#14;  javascript:alert(\'XSS\');">', '<IMG src="alert(&#039;XSS&#039;);">'];
@@ -175,7 +175,7 @@ public function providerTestFilterXss() {
     // Double open angle brackets.
     // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#Double_open_angle_brackets
     // @see http://ha.ckers.org/blog/20060611/hotbot-xss-vulnerability/ to
-    //      understand why this is a vulnerability.
+    // understand why this is a vulnerability.
     $data[] = ['<iframe src=http://ha.ckers.org/scriptlet.html <', '<iframe src="http://ha.ckers.org/scriptlet.html">'];
 
     // Escaping JavaScript escapes.
diff --git a/web/core/modules/field/migrations/state/field.migrate_drupal.yml b/web/core/modules/field/migrations/state/field.migrate_drupal.yml
index 02fae2e71a..826b2bb85f 100644
--- a/web/core/modules/field/migrations/state/field.migrate_drupal.yml
+++ b/web/core/modules/field/migrations/state/field.migrate_drupal.yml
@@ -1,5 +1,7 @@
 finished:
   6:
+    nodereference: core
+    userreference: core
     content: field
     email: core
     # Phone does not use a migrate field plugin so it is added here.
diff --git a/web/core/modules/field/src/Plugin/migrate/process/d7/FieldOptionTranslation.php b/web/core/modules/field/src/Plugin/migrate/process/d7/FieldOptionTranslation.php
index a7208bec1b..3831bfcb59 100644
--- a/web/core/modules/field/src/Plugin/migrate/process/d7/FieldOptionTranslation.php
+++ b/web/core/modules/field/src/Plugin/migrate/process/d7/FieldOptionTranslation.php
@@ -42,6 +42,7 @@ public function transform($value, MigrateExecutableInterface $migrate_executable
           break;
 
         default:
+          $new_allowed_values = $allowed_values;
       }
     }
     return ["settings.allowed_values.$translation_key", $new_allowed_values];
diff --git a/web/core/modules/field/src/Plugin/migrate/source/d7/FieldInstance.php b/web/core/modules/field/src/Plugin/migrate/source/d7/FieldInstance.php
index be28a8fd46..d23c1b52c4 100644
--- a/web/core/modules/field/src/Plugin/migrate/source/d7/FieldInstance.php
+++ b/web/core/modules/field/src/Plugin/migrate/source/d7/FieldInstance.php
@@ -148,10 +148,10 @@ public function prepareRow(Row $row) {
     if ($row->getSourceProperty('entity_type') == 'node') {
       $language_content_type_bundle = (int) $this->variableGet('language_content_type_' . $row->getSourceProperty('bundle'), 0);
       // language_content_type_[bundle] may be
-      //   - 0: no language support
-      //   - 1: language assignment support
-      //   - 2: node translation support
-      //   - 4: entity translation support
+      // - 0: no language support
+      // - 1: language assignment support
+      // - 2: node translation support
+      // - 4: entity translation support
       if ($language_content_type_bundle === 2 || ($language_content_type_bundle === 4 && $row->getSourceProperty('translatable'))) {
         $translatable = TRUE;
       }
diff --git a/web/core/modules/field/src/Plugin/migrate/source/d7/FieldOptionTranslation.php b/web/core/modules/field/src/Plugin/migrate/source/d7/FieldOptionTranslation.php
index 21a8bbea6e..5569541d2d 100644
--- a/web/core/modules/field/src/Plugin/migrate/source/d7/FieldOptionTranslation.php
+++ b/web/core/modules/field/src/Plugin/migrate/source/d7/FieldOptionTranslation.php
@@ -75,6 +75,7 @@ public function getIds() {
       [
         'language' => ['type' => 'string'],
         'property' => ['type' => 'string'],
+        'bundle' => ['type' => 'string'],
       ];
   }
 
diff --git a/web/core/modules/field/src/Plugin/migrate/source/d7/ViewMode.php b/web/core/modules/field/src/Plugin/migrate/source/d7/ViewMode.php
index 039960a4ed..ebfb790a74 100644
--- a/web/core/modules/field/src/Plugin/migrate/source/d7/ViewMode.php
+++ b/web/core/modules/field/src/Plugin/migrate/source/d7/ViewMode.php
@@ -3,7 +3,12 @@
 namespace Drupal\field\Plugin\migrate\source\d7;
 
 /**
- * The view mode source class.
+ * Drupal 7 view mode source from database.
+ *
+ * For available configuration keys, refer to the parent classes.
+ *
+ * @see \Drupal\migrate\Plugin\migrate\source\SqlBase
+ * @see \Drupal\migrate\Plugin\migrate\source\SourcePluginBase
  *
  * @MigrateSource(
  *   id = "d7_view_mode",
diff --git a/web/core/modules/field/tests/modules/field_test/field_test.module b/web/core/modules/field/tests/modules/field_test/field_test.module
index 8b987467df..2ec952dd19 100644
--- a/web/core/modules/field/tests/modules/field_test/field_test.module
+++ b/web/core/modules/field/tests/modules/field_test/field_test.module
@@ -49,8 +49,8 @@
  *   $mem = field_test_memorize();
  *
  *   // make sure hook_field_storage_config_create() is invoked correctly
- *   assertEqual(count($mem['field_test_field_storage_config_create']), 1);
- *   assertEqual($mem['field_test_field_storage_config_create'][0], array($field));
+ *   assertEquals(1, count($mem['field_test_field_storage_config_create']));
+ *   assertEquals(array($field), $mem['field_test_field_storage_config_create'][0]);
  * @endcode
  *
  * @param $key
diff --git a/web/core/modules/field/tests/src/Functional/EntityReference/EntityReferenceAutoCreateTest.php b/web/core/modules/field/tests/src/Functional/EntityReference/EntityReferenceAutoCreateTest.php
index 21392ab2b8..83a6f05787 100644
--- a/web/core/modules/field/tests/src/Functional/EntityReference/EntityReferenceAutoCreateTest.php
+++ b/web/core/modules/field/tests/src/Functional/EntityReference/EntityReferenceAutoCreateTest.php
@@ -229,17 +229,19 @@ public function testMultipleTargetBundles() {
     //   a way to catch and assert user-triggered errors.
 
     // Test the case when the field config settings are inconsistent.
+    // @code
     // unset($handler_settings['auto_create_bundle']);
     // $field_config->setSetting('handler_settings', $handler_settings);
     // $field_config->save();
     //
     // $this->drupalGet('node/add/' . $this->referencingType);
     // $error_message = sprintf(
-    //  "Create referenced entities if they don't already exist option is enabled but a specific destination bundle is not set. You should re-visit and fix the settings of the '%s' (%s) field.",
-    //  $field_config->getLabel(),
-    //  $field_config->getName()
+    //   "Create referenced entities if they don't already exist option is enabled but a specific destination bundle is not set. You should re-visit and fix the settings of the '%s' (%s) field.",
+    //   $field_config->getLabel(),
+    //   $field_config->getName()
     // );
     // $this->assertErrorLogged($error_message);
+    // @endcode
   }
 
   /**
diff --git a/web/core/modules/field/tests/src/Functional/FieldTestBase.php b/web/core/modules/field/tests/src/Functional/FieldTestBase.php
index c33bfe6fd4..4656ed5dca 100644
--- a/web/core/modules/field/tests/src/Functional/FieldTestBase.php
+++ b/web/core/modules/field/tests/src/Functional/FieldTestBase.php
@@ -58,7 +58,7 @@ public function assertFieldValues(EntityInterface $entity, $field_name, $expecte
     // Filter out empty values so that they don't mess with the assertions.
     $field->filterEmptyItems();
     $values = $field->getValue();
-    $this->assertEquals(count($expected_values), count($values), 'Expected number of values were saved.');
+    $this->assertSameSize($expected_values, $values, 'Expected number of values were saved.');
     foreach ($expected_values as $key => $value) {
       $this->assertEquals($value, $values[$key][$column], new FormattableMarkup('Value @value was saved correctly.', ['@value' => $value]));
     }
diff --git a/web/core/modules/field/tests/src/Functional/FormTest.php b/web/core/modules/field/tests/src/Functional/FormTest.php
index fb281b97fd..c1eeb7f2f1 100644
--- a/web/core/modules/field/tests/src/Functional/FormTest.php
+++ b/web/core/modules/field/tests/src/Functional/FormTest.php
@@ -366,8 +366,7 @@ public function testFieldFormUnlimitedRequired() {
     $this->assertTrue(isset($element[0]), 'Required symbol added field label.');
     // Check that the label of the field input is visually hidden and contains
     // the field title and an indication of the delta for a11y.
-    $element = $this->xpath('//label[@for=:for and contains(@class, "visually-hidden") and contains(text(), :value)]', [':for' => 'edit-field-unlimited-0-value', ':value' => $this->field['label'] . ' (value 1)']);
-    $this->assertTrue(isset($element[0]), 'Required symbol not added for field input.');
+    $this->assertSession()->elementExists('xpath', "//label[@for='edit-field-unlimited-0-value' and contains(@class, 'visually-hidden') and contains(text(), '{$this->field['label']} (value 1)')]");
   }
 
   /**
diff --git a/web/core/modules/field/tests/src/Functional/Views/FieldUITest.php b/web/core/modules/field/tests/src/Functional/Views/FieldUITest.php
index 9850d23065..f26fbd7caa 100644
--- a/web/core/modules/field/tests/src/Functional/Views/FieldUITest.php
+++ b/web/core/modules/field/tests/src/Functional/Views/FieldUITest.php
@@ -150,16 +150,13 @@ public function testBooleanFilterHandler() {
     $this->assertSession()->statusCodeEquals(200);
     // Verify that using a boolean field as a filter also results in using the
     // boolean plugin.
-    $option = $this->xpath('//label[@for="edit-options-value-1"]');
-    $this->assertEquals(t('True'), $option[0]->getText());
-    $option = $this->xpath('//label[@for="edit-options-value-0"]');
-    $this->assertEquals(t('False'), $option[0]->getText());
+    $this->assertSession()->elementTextEquals('xpath', '//label[@for="edit-options-value-1"]', 'True');
+    $this->assertSession()->elementTextEquals('xpath', '//label[@for="edit-options-value-0"]', 'False');
 
     // Expose the filter and see if the 'Any' option is added and if we can save
     // it.
     $this->submitForm([], 'Expose filter');
-    $option = $this->xpath('//label[@for="edit-options-value-all"]');
-    $this->assertEquals(t('- Any -'), $option[0]->getText());
+    $this->assertSession()->elementTextEquals('xpath', '//label[@for="edit-options-value-all"]', '- Any -');
     $this->submitForm(['options[value]' => 'All', 'options[expose][required]' => FALSE], 'Apply');
     $this->submitForm([], 'Save');
     $this->drupalGet('/admin/structure/views/nojs/handler/test_view_fieldapi/default/filter/field_boolean_value');
diff --git a/web/core/modules/field/tests/src/Kernel/BulkDeleteTest.php b/web/core/modules/field/tests/src/Kernel/BulkDeleteTest.php
index 4b155b5f41..78daf5261d 100644
--- a/web/core/modules/field/tests/src/Kernel/BulkDeleteTest.php
+++ b/web/core/modules/field/tests/src/Kernel/BulkDeleteTest.php
@@ -64,7 +64,7 @@ public function checkHooksInvocations($expected_hooks, $actual_hooks) {
       $actual_invocations = $actual_hooks[$hook];
 
       // Check that the number of invocations is correct.
-      $this->assertSame(count($invocations), count($actual_invocations), "$hook() was called the expected number of times.");
+      $this->assertSameSize($invocations, $actual_invocations, "$hook() was called the expected number of times.");
 
       // Check that the hook was called for each expected argument.
       foreach ($invocations as $argument) {
diff --git a/web/core/modules/field/tests/src/Kernel/Migrate/d7/MigrateFieldInstanceOptionTranslationTest.php b/web/core/modules/field/tests/src/Kernel/Migrate/d7/MigrateFieldInstanceOptionTranslationTest.php
new file mode 100644
index 0000000000..10ee6dfe70
--- /dev/null
+++ b/web/core/modules/field/tests/src/Kernel/Migrate/d7/MigrateFieldInstanceOptionTranslationTest.php
@@ -0,0 +1,86 @@
+<?php
+
+namespace Drupal\Tests\field\Kernel\Migrate\d7;
+
+use Drupal\Tests\migrate_drupal\Kernel\d7\MigrateDrupal7TestBase;
+
+/**
+ * Migrate field instance option translations.
+ *
+ * @group migrate_drupal_7
+ */
+class MigrateFieldInstanceOptionTranslationTest extends MigrateDrupal7TestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $modules = [
+    'comment',
+    'config_translation',
+    'datetime',
+    'file',
+    'image',
+    'language',
+    'link',
+    'locale',
+    'menu_ui',
+    'node',
+    'system',
+    'taxonomy',
+    'telephone',
+    'text',
+  ];
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp(): void {
+    parent::setUp();
+    $this->installConfig(['node']);
+    $this->executeMigration('language');
+    $this->migrateFields();
+    $this->executeMigrations([
+      'd7_field_option_translation',
+      'd7_field_instance_option_translation',
+    ]);
+  }
+
+  /**
+   * Migrate field instance option translations.
+   */
+  public function testFieldInstanceOptionTranslation() {
+    $language_manager = $this->container->get('language_manager');
+
+    /** @var \Drupal\language\Config\LanguageConfigOverride $config_translation */
+    $config_translation = $language_manager->getLanguageConfigOverride('fr', 'field.field.node.blog.field_boolean');
+    $this->assertNull($config_translation->get('settings'));
+
+    $config_translation = $language_manager->getLanguageConfigOverride('is', 'field.field.node.blog.field_boolean');
+    $option_translation = [
+      'off_label' => 'is - Off',
+      'on_label' => 'is - 1',
+    ];
+
+    $this->assertSame($option_translation, $config_translation->get('settings'));
+    $config_translation = $language_manager->getLanguageConfigOverride('fr', 'field.field.node.test_content_type.field_boolean');
+    $this->assertNull($config_translation->get('settings'));
+
+    $config_translation = $language_manager->getLanguageConfigOverride('is', 'field.field.node.test_content_type.field_boolean');
+    $this->assertSame($option_translation, $config_translation->get('settings'));
+
+    $config_translation = $language_manager->getLanguageConfigOverride('fr', 'field.field.node.article.field_checkbox');
+    $option_translation = [
+      'off_label' => 'fr - Stop',
+      'on_label' => 'Go',
+    ];
+    $this->assertSame($option_translation, $config_translation->get('settings'));
+
+    $config_translation = $language_manager->getLanguageConfigOverride('is', 'field.field.node.article.field_checkbox');
+    $option_translation = [
+      'off_label' => 'is - Stop',
+      'on_label' => 'is - Go',
+    ];
+    $this->assertSame($option_translation, $config_translation->get('settings'));
+  }
+
+}
diff --git a/web/core/modules/field/tests/src/Kernel/Migrate/d7/MigrateFieldOptionTranslationTest.php b/web/core/modules/field/tests/src/Kernel/Migrate/d7/MigrateFieldOptionTranslationTest.php
index aa9236174e..08f258456d 100644
--- a/web/core/modules/field/tests/src/Kernel/Migrate/d7/MigrateFieldOptionTranslationTest.php
+++ b/web/core/modules/field/tests/src/Kernel/Migrate/d7/MigrateFieldOptionTranslationTest.php
@@ -106,8 +106,48 @@ public function testFieldOptionTranslation() {
     ];
     $this->assertSame($allowed_values, $config_translation->get('settings.allowed_values'));
 
+    $config_translation = $language_manager->getLanguageConfigOverride('fr', 'field.storage.node.field_boolean');
+    $this->assertNull($config_translation->get('settings.allowed_values'));
+
+    $config_translation = $language_manager->getLanguageConfigOverride('is', 'field.storage.node.field_boolean');
+    $allowed_values = [
+      0 => [
+        0 => 'Off',
+        1 => '1',
+      ],
+      1 => [
+        0 => 'Off',
+        1 => '1',
+      ],
+    ];
+    $this->assertSame($allowed_values, $config_translation->get('settings.allowed_values'));
+
+    $config_translation = $language_manager->getLanguageConfigOverride('fr', 'field.storage.node.field_checkbox');
+    $allowed_values = [
+      0 => [
+        0 => 'Stop',
+        1 => 'Go',
+      ],
+      1 => [
+        0 => 'Stop',
+        1 => 'Go',
+      ],
+    ];
+    $this->assertSame($allowed_values, $config_translation->get('settings.allowed_values'));
+    $config_translation = $language_manager->getLanguageConfigOverride('is', 'field.storage.node.field_checkbox');
+    $allowed_values = [
+      0 => [
+        0 => 'Stop',
+        1 => 'Go',
+      ],
+      1 => [
+        0 => 'Stop',
+        1 => 'Go',
+      ],
+    ];
+    $this->assertSame($allowed_values, $config_translation->get('settings.allowed_values'));
     // Ensure that the count query works as expected.
-    $this->assertCount(16, $this->getMigration('d7_field_option_translation')->getSourcePlugin());
+    $this->assertCount(20, $this->getMigration('d7_field_option_translation')->getSourcePlugin());
   }
 
 }
diff --git a/web/core/modules/field/tests/src/Kernel/Migrate/d7/MigrateFieldTest.php b/web/core/modules/field/tests/src/Kernel/Migrate/d7/MigrateFieldTest.php
index 0ab9010c76..1ad4c722cf 100644
--- a/web/core/modules/field/tests/src/Kernel/Migrate/d7/MigrateFieldTest.php
+++ b/web/core/modules/field/tests/src/Kernel/Migrate/d7/MigrateFieldTest.php
@@ -182,10 +182,10 @@ public function testFields() {
     }, iterator_to_array($migration->getIdMap()->getMessages()));
     sort($errors);
     $this->assertCount(4, $errors);
-    $this->assertEquals($errors[0], 'Can\'t migrate source field field_text_long_plain_filtered configured with both plain text and filtered text processing. See https://www.drupal.org/docs/8/upgrade/known-issues-when-upgrading-from-drupal-6-or-7-to-drupal-8#plain-text');
-    $this->assertEquals($errors[1], 'Can\'t migrate source field field_text_plain_filtered configured with both plain text and filtered text processing. See https://www.drupal.org/docs/8/upgrade/known-issues-when-upgrading-from-drupal-6-or-7-to-drupal-8#plain-text');
-    $this->assertEquals($errors[2], 'Can\'t migrate source field field_text_sum_plain of type text_with_summary configured with plain text processing. See https://www.drupal.org/docs/8/upgrade/known-issues-when-upgrading-from-drupal-6-or-7-to-drupal-8#plain-text');
-    $this->assertEquals($errors[3], 'Can\'t migrate source field field_text_sum_plain_filtered of type text_with_summary configured with plain text processing. See https://www.drupal.org/docs/8/upgrade/known-issues-when-upgrading-from-drupal-6-or-7-to-drupal-8#plain-text');
+    $this->assertEquals('Can\'t migrate source field field_text_long_plain_filtered configured with both plain text and filtered text processing. See https://www.drupal.org/docs/8/upgrade/known-issues-when-upgrading-from-drupal-6-or-7-to-drupal-8#plain-text', $errors[0]);
+    $this->assertEquals('Can\'t migrate source field field_text_plain_filtered configured with both plain text and filtered text processing. See https://www.drupal.org/docs/8/upgrade/known-issues-when-upgrading-from-drupal-6-or-7-to-drupal-8#plain-text', $errors[1]);
+    $this->assertEquals('Can\'t migrate source field field_text_sum_plain of type text_with_summary configured with plain text processing. See https://www.drupal.org/docs/8/upgrade/known-issues-when-upgrading-from-drupal-6-or-7-to-drupal-8#plain-text', $errors[2]);
+    $this->assertEquals('Can\'t migrate source field field_text_sum_plain_filtered of type text_with_summary configured with plain text processing. See https://www.drupal.org/docs/8/upgrade/known-issues-when-upgrading-from-drupal-6-or-7-to-drupal-8#plain-text', $errors[3]);
   }
 
 }
diff --git a/web/core/modules/field/tests/src/Unit/FieldConfigEntityUnitTest.php b/web/core/modules/field/tests/src/Unit/FieldConfigEntityUnitTest.php
index 240e580c21..87945c8069 100644
--- a/web/core/modules/field/tests/src/Unit/FieldConfigEntityUnitTest.php
+++ b/web/core/modules/field/tests/src/Unit/FieldConfigEntityUnitTest.php
@@ -121,22 +121,12 @@ public function testCalculateDependencies() {
       ->method('getBundleConfigDependency')
       ->will($this->returnValue(['type' => 'config', 'name' => 'test.test_entity_type.id']));
 
-    $this->entityTypeManager->expects($this->at(0))
-      ->method('getDefinition')
-      ->with($this->entityTypeId)
-      ->willReturn($this->entityType);
-    $this->entityTypeManager->expects($this->at(1))
-      ->method('getDefinition')
-      ->with($this->entityTypeId)
-      ->willReturn($this->entityType);
-    $this->entityTypeManager->expects($this->at(2))
-      ->method('getDefinition')
-      ->with($this->entityTypeId)
-      ->willReturn($this->entityType);
-    $this->entityTypeManager->expects($this->at(3))
+    $this->entityTypeManager->expects($this->any())
       ->method('getDefinition')
-      ->with('test_entity_type')
-      ->willReturn($target_entity_type);
+      ->willReturnMap([
+        [$this->entityTypeId, TRUE, $this->entityType],
+        ['test_entity_type', TRUE, $target_entity_type],
+      ]);
 
     $this->fieldTypePluginManager->expects($this->any())
       ->method('getDefinition')
@@ -179,22 +169,12 @@ public function testCalculateDependenciesIncorrectBundle() {
       'bundle_entity_type' => 'bundle_entity_type',
     ]);
 
-    $this->entityTypeManager->expects($this->at(0))
-      ->method('getDefinition')
-      ->with($this->entityTypeId)
-      ->willReturn($this->entityType);
-    $this->entityTypeManager->expects($this->at(1))
-      ->method('getDefinition')
-      ->with($this->entityTypeId)
-      ->willReturn($this->entityType);
-    $this->entityTypeManager->expects($this->at(2))
-      ->method('getDefinition')
-      ->with($this->entityTypeId)
-      ->willReturn($this->entityType);
-    $this->entityTypeManager->expects($this->at(3))
+    $this->entityTypeManager->expects($this->any())
       ->method('getDefinition')
-      ->with('test_entity_type')
-      ->willReturn($target_entity_type);
+      ->willReturnMap([
+        [$this->entityTypeId, TRUE, $this->entityType],
+        ['test_entity_type', TRUE, $target_entity_type],
+      ]);
 
     $this->fieldTypePluginManager->expects($this->any())
       ->method('getDefinition')
diff --git a/web/core/modules/field_ui/tests/src/FunctionalJavascript/ManageDisplayTest.php b/web/core/modules/field_ui/tests/src/FunctionalJavascript/ManageDisplayTest.php
index 17cc3e4507..d99b0021d4 100644
--- a/web/core/modules/field_ui/tests/src/FunctionalJavascript/ManageDisplayTest.php
+++ b/web/core/modules/field_ui/tests/src/FunctionalJavascript/ManageDisplayTest.php
@@ -182,7 +182,7 @@ public function testFormatterUI() {
     $id = 'node.' . $this->type . '.default';
     /** @var \Drupal\Core\Entity\Display\EntityViewDisplayInterface $display */
     $display = $display_storage->loadUnchanged($id);
-    $this->assertEquals($display->getRenderer('field_test')->getThirdPartySetting('field_third_party_test', 'field_test_field_formatter_third_party_settings_form'), 'foo');
+    $this->assertEquals('foo', $display->getRenderer('field_test')->getThirdPartySetting('field_third_party_test', 'field_test_field_formatter_third_party_settings_form'));
     $this->assertContains('field_third_party_test', $display->calculateDependencies()->getDependencies()['module'], 'The display has a dependency on field_third_party_test module.');
 
     // Change the formatter to an empty setting and validate it's initialized
@@ -329,7 +329,7 @@ public function testWidgetUI() {
 
     /** @var \Drupal\Core\Entity\Display\EntityFormDisplayInterface $display */
     $display = $form_storage->loadUnchanged('node.' . $this->type . '.default');
-    $this->assertEquals($display->getRenderer('field_test')->getThirdPartySetting('field_third_party_test', 'field_test_widget_third_party_settings_form'), 'foo');
+    $this->assertEquals('foo', $display->getRenderer('field_test')->getThirdPartySetting('field_third_party_test', 'field_test_widget_third_party_settings_form'));
     $this->assertContains('field_third_party_test', $display->calculateDependencies()->getDependencies()['module'], 'Form display does not have a dependency on field_third_party_test module.');
 
     // Creates a new field that can not be used with the multiple formatter.
@@ -395,7 +395,7 @@ protected function assertFieldSelectOptions($field, array $expected_options, $se
     $select_options = $field->findAll('xpath', 'option');
 
     // Validate the number of options.
-    $this->assertCount(count($expected_options), $select_options);
+    $this->assertSameSize($expected_options, $select_options);
 
     // Validate the options and expected order.
     foreach ($select_options as $key => $option) {
diff --git a/web/core/modules/file/tests/src/Functional/FileFieldWidgetTest.php b/web/core/modules/file/tests/src/Functional/FileFieldWidgetTest.php
index f24994763c..fb9285ed02 100644
--- a/web/core/modules/file/tests/src/Functional/FileFieldWidgetTest.php
+++ b/web/core/modules/file/tests/src/Functional/FileFieldWidgetTest.php
@@ -106,8 +106,7 @@ public function testSingleValuedWidget() {
     $this->assertSession()->buttonExists('Upload');
     // Test label has correct 'for' attribute.
     $input = $this->assertSession()->fieldExists("files[{$field_name}_0]");
-    $label = $this->xpath('//label[@for="' . $input->getAttribute('id') . '"]');
-    $this->assertTrue(isset($label[0]), 'Label for upload found.');
+    $this->assertSession()->elementExists('xpath', '//label[@for="' . $input->getAttribute('id') . '"]');
 
     // Save the node and ensure it does not have the file.
     $this->submitForm([], 'Save');
@@ -226,7 +225,7 @@ public function testMultiValuedWidget() {
     // Try to upload multiple files, but fewer than the maximum.
     $nid = $this->uploadNodeFiles($upload_files_node_creation, $field_name, $type_name, TRUE, []);
     $node = $node_storage->loadUnchanged($nid);
-    $this->assertSame(count($upload_files_node_creation), count($node->{$field_name}), 'Node was successfully saved with multiple files.');
+    $this->assertSameSize($upload_files_node_creation, $node->{$field_name}, 'Node was successfully saved with multiple files.');
 
     // Try to upload exactly the allowed number of files on revision.
     $this->uploadNodeFile($test_file, $field_name, $node->id(), 1, [], TRUE);
diff --git a/web/core/modules/filter/src/Entity/FilterFormat.php b/web/core/modules/filter/src/Entity/FilterFormat.php
index abd9b6aae8..8b846be57a 100644
--- a/web/core/modules/filter/src/Entity/FilterFormat.php
+++ b/web/core/modules/filter/src/Entity/FilterFormat.php
@@ -357,8 +357,8 @@ public function getHtmlRestrictions() {
                 }
                 // Both list an array of attribute values; do an intersection,
                 // where we take into account that a value of:
-                //  - TRUE means the attribute value is allowed;
-                //  - FALSE means the attribute value is forbidden;
+                // - TRUE means the attribute value is allowed;
+                // - FALSE means the attribute value is forbidden;
                 // hence we keep the ANDed result.
                 else {
                   $intersection[$tag] = array_intersect_key($intersection[$tag], $new_attributes);
diff --git a/web/core/modules/filter/src/Plugin/migrate/source/d6/FilterFormat.php b/web/core/modules/filter/src/Plugin/migrate/source/d6/FilterFormat.php
index de9ab4c238..8dd2220184 100644
--- a/web/core/modules/filter/src/Plugin/migrate/source/d6/FilterFormat.php
+++ b/web/core/modules/filter/src/Plugin/migrate/source/d6/FilterFormat.php
@@ -8,6 +8,11 @@
 /**
  * Drupal 6 filter source from database.
  *
+ * For available configuration keys, refer to the parent classes.
+ *
+ * @see \Drupal\migrate\Plugin\migrate\source\SqlBase
+ * @see \Drupal\migrate\Plugin\migrate\source\SourcePluginBase
+ *
  * @MigrateSource(
  *   id = "d6_filter_format",
  *   source_module = "filter"
diff --git a/web/core/modules/filter/src/Plugin/migrate/source/d7/FilterFormat.php b/web/core/modules/filter/src/Plugin/migrate/source/d7/FilterFormat.php
index 13438f2923..c0db5177be 100644
--- a/web/core/modules/filter/src/Plugin/migrate/source/d7/FilterFormat.php
+++ b/web/core/modules/filter/src/Plugin/migrate/source/d7/FilterFormat.php
@@ -8,6 +8,11 @@
 /**
  * Drupal 7 filter source from database.
  *
+ * For available configuration keys, refer to the parent classes.
+ *
+ * @see \Drupal\migrate\Plugin\migrate\source\SqlBase
+ * @see \Drupal\migrate\Plugin\migrate\source\SourcePluginBase
+ *
  * @MigrateSource(
  *   id = "d7_filter_format",
  *   source_module = "filter"
diff --git a/web/core/modules/filter/tests/src/Kernel/FilterKernelTest.php b/web/core/modules/filter/tests/src/Kernel/FilterKernelTest.php
index d471600a77..f26a1b4286 100644
--- a/web/core/modules/filter/tests/src/Kernel/FilterKernelTest.php
+++ b/web/core/modules/filter/tests/src/Kernel/FilterKernelTest.php
@@ -937,116 +937,116 @@ public function testUrlFilterContent() {
   public function testHtmlCorrectorFilter() {
     // Tag closing.
     $f = Html::normalize('<p>text');
-    $this->assertEquals($f, '<p>text</p>', 'HTML corrector -- tag closing at the end of input.');
+    $this->assertEquals('<p>text</p>', $f, 'HTML corrector -- tag closing at the end of input.');
 
     $f = Html::normalize('<p>text<p><p>text');
-    $this->assertEquals($f, '<p>text</p><p></p><p>text</p>', 'HTML corrector -- tag closing.');
+    $this->assertEquals('<p>text</p><p></p><p>text</p>', $f, 'HTML corrector -- tag closing.');
 
     $f = Html::normalize("<ul><li>e1<li>e2");
-    $this->assertEquals($f, "<ul><li>e1</li><li>e2</li></ul>", 'HTML corrector -- unclosed list tags.');
+    $this->assertEquals("<ul><li>e1</li><li>e2</li></ul>", $f, 'HTML corrector -- unclosed list tags.');
 
     $f = Html::normalize('<div id="d">content');
-    $this->assertEquals($f, '<div id="d">content</div>', 'HTML corrector -- unclosed tag with attribute.');
+    $this->assertEquals('<div id="d">content</div>', $f, 'HTML corrector -- unclosed tag with attribute.');
 
     // XHTML slash for empty elements.
     $f = Html::normalize('<hr><br>');
-    $this->assertEquals($f, '<hr /><br />', 'HTML corrector -- XHTML closing slash.');
+    $this->assertEquals('<hr /><br />', $f, 'HTML corrector -- XHTML closing slash.');
 
     $f = Html::normalize('<P>test</P>');
-    $this->assertEquals($f, '<p>test</p>', 'HTML corrector -- Convert uppercased tags to proper lowercased ones.');
+    $this->assertEquals('<p>test</p>', $f, 'HTML corrector -- Convert uppercased tags to proper lowercased ones.');
 
     $f = Html::normalize('<P>test</p>');
-    $this->assertEquals($f, '<p>test</p>', 'HTML corrector -- Convert uppercased tags to proper lowercased ones.');
+    $this->assertEquals('<p>test</p>', $f, 'HTML corrector -- Convert uppercased tags to proper lowercased ones.');
 
     $f = Html::normalize('test<hr />');
-    $this->assertEquals($f, 'test<hr />', 'HTML corrector -- Let proper XHTML pass through.');
+    $this->assertEquals('test<hr />', $f, 'HTML corrector -- Let proper XHTML pass through.');
 
     $f = Html::normalize('test<hr/>');
-    $this->assertEquals($f, 'test<hr />', 'HTML corrector -- Let proper XHTML pass through, but ensure there is a single space before the closing slash.');
+    $this->assertEquals('test<hr />', $f, 'HTML corrector -- Let proper XHTML pass through, but ensure there is a single space before the closing slash.');
 
     $f = Html::normalize('test<hr    />');
-    $this->assertEquals($f, 'test<hr />', 'HTML corrector -- Let proper XHTML pass through, but ensure there are not too many spaces before the closing slash.');
+    $this->assertEquals('test<hr />', $f, 'HTML corrector -- Let proper XHTML pass through, but ensure there are not too many spaces before the closing slash.');
 
     $f = Html::normalize('<span class="test" />');
-    $this->assertEquals($f, '<span class="test"></span>', 'HTML corrector -- Convert XHTML that is properly formed but that would not be compatible with typical HTML user agents.');
+    $this->assertEquals('<span class="test"></span>', $f, 'HTML corrector -- Convert XHTML that is properly formed but that would not be compatible with typical HTML user agents.');
 
     $f = Html::normalize('test1<br class="test">test2');
-    $this->assertEquals($f, 'test1<br class="test" />test2', 'HTML corrector -- Automatically close single tags.');
+    $this->assertEquals('test1<br class="test" />test2', $f, 'HTML corrector -- Automatically close single tags.');
 
     $f = Html::normalize('line1<hr>line2');
-    $this->assertEquals($f, 'line1<hr />line2', 'HTML corrector -- Automatically close single tags.');
+    $this->assertEquals('line1<hr />line2', $f, 'HTML corrector -- Automatically close single tags.');
 
     $f = Html::normalize('line1<HR>line2');
-    $this->assertEquals($f, 'line1<hr />line2', 'HTML corrector -- Automatically close single tags.');
+    $this->assertEquals('line1<hr />line2', $f, 'HTML corrector -- Automatically close single tags.');
 
     $f = Html::normalize('<img src="http://example.com/test.jpg">test</img>');
-    $this->assertEquals($f, '<img src="http://example.com/test.jpg" />test', 'HTML corrector -- Automatically close single tags.');
+    $this->assertEquals('<img src="http://example.com/test.jpg" />test', $f, 'HTML corrector -- Automatically close single tags.');
 
     $f = Html::normalize('<br></br>');
-    $this->assertEquals($f, '<br />', "HTML corrector -- Transform empty tags to a single closed tag if the tag's content model is EMPTY.");
+    $this->assertEquals('<br />', $f, "HTML corrector -- Transform empty tags to a single closed tag if the tag's content model is EMPTY.");
 
     $f = Html::normalize('<div></div>');
-    $this->assertEquals($f, '<div></div>', "HTML corrector -- Do not transform empty tags to a single closed tag if the tag's content model is not EMPTY.");
+    $this->assertEquals('<div></div>', $f, "HTML corrector -- Do not transform empty tags to a single closed tag if the tag's content model is not EMPTY.");
 
     $f = Html::normalize('<p>line1<br/><hr/>line2</p>');
-    $this->assertEquals($f, '<p>line1<br /></p><hr />line2', 'HTML corrector -- Move non-inline elements outside of inline containers.');
+    $this->assertEquals('<p>line1<br /></p><hr />line2', $f, 'HTML corrector -- Move non-inline elements outside of inline containers.');
 
     $f = Html::normalize('<p>line1<div>line2</div></p>');
-    $this->assertEquals($f, '<p>line1</p><div>line2</div>', 'HTML corrector -- Move non-inline elements outside of inline containers.');
+    $this->assertEquals('<p>line1</p><div>line2</div>', $f, 'HTML corrector -- Move non-inline elements outside of inline containers.');
 
     $f = Html::normalize('<p>test<p>test</p>\n');
-    $this->assertEquals($f, '<p>test</p><p>test</p>\n', 'HTML corrector -- Auto-close improperly nested tags.');
+    $this->assertEquals('<p>test</p><p>test</p>\n', $f, 'HTML corrector -- Auto-close improperly nested tags.');
 
     $f = Html::normalize('<p>Line1<br><STRONG>bold stuff</b>');
-    $this->assertEquals($f, '<p>Line1<br /><strong>bold stuff</strong></p>', 'HTML corrector -- Properly close unclosed tags, and remove useless closing tags.');
+    $this->assertEquals('<p>Line1<br /><strong>bold stuff</strong></p>', $f, 'HTML corrector -- Properly close unclosed tags, and remove useless closing tags.');
 
     $f = Html::normalize('test <!-- this is a comment -->');
-    $this->assertEquals($f, 'test <!-- this is a comment -->', 'HTML corrector -- Do not touch HTML comments.');
+    $this->assertEquals('test <!-- this is a comment -->', $f, 'HTML corrector -- Do not touch HTML comments.');
 
     $f = Html::normalize('test <!--this is a comment-->');
-    $this->assertEquals($f, 'test <!--this is a comment-->', 'HTML corrector -- Do not touch HTML comments.');
+    $this->assertEquals('test <!--this is a comment-->', $f, 'HTML corrector -- Do not touch HTML comments.');
 
     $f = Html::normalize('test <!-- comment <p>another
     <strong>multiple</strong> line
     comment</p> -->');
-    $this->assertEquals($f, 'test <!-- comment <p>another
+    $this->assertEquals('test <!-- comment <p>another
     <strong>multiple</strong> line
-    comment</p> -->', 'HTML corrector -- Do not touch HTML comments.');
+    comment</p> -->', $f, 'HTML corrector -- Do not touch HTML comments.');
 
     $f = Html::normalize('test <!-- comment <p>another comment</p> -->');
-    $this->assertEquals($f, 'test <!-- comment <p>another comment</p> -->', 'HTML corrector -- Do not touch HTML comments.');
+    $this->assertEquals('test <!-- comment <p>another comment</p> -->', $f, 'HTML corrector -- Do not touch HTML comments.');
 
     $f = Html::normalize('test <!--break-->');
-    $this->assertEquals($f, 'test <!--break-->', 'HTML corrector -- Do not touch HTML comments.');
+    $this->assertEquals('test <!--break-->', $f, 'HTML corrector -- Do not touch HTML comments.');
 
     $f = Html::normalize('<p>test\n</p>\n');
-    $this->assertEquals($f, '<p>test\n</p>\n', 'HTML corrector -- New-lines are accepted and kept as-is.');
+    $this->assertEquals('<p>test\n</p>\n', $f, 'HTML corrector -- New-lines are accepted and kept as-is.');
 
     // cSpell:disable
     $f = Html::normalize('<p>دروبال');
-    $this->assertEquals($f, '<p>دروبال</p>', 'HTML corrector -- Encoding is correctly kept.');
+    $this->assertEquals('<p>دروبال</p>', $f, 'HTML corrector -- Encoding is correctly kept.');
     // cSpell:enable
 
     $f = Html::normalize('<script>alert("test")</script>');
-    $this->assertEquals($f, '<script>
+    $this->assertEquals('<script>
 <!--//--><![CDATA[// ><!--
 alert("test")
 //--><!]]>
-</script>', 'HTML corrector -- CDATA added to script element');
+</script>', $f, 'HTML corrector -- CDATA added to script element');
 
     $f = Html::normalize('<p><script>alert("test")</script></p>');
-    $this->assertEquals($f, '<p><script>
+    $this->assertEquals('<p><script>
 <!--//--><![CDATA[// ><!--
 alert("test")
 //--><!]]>
-</script></p>', 'HTML corrector -- CDATA added to a nested script element');
+</script></p>', $f, 'HTML corrector -- CDATA added to a nested script element');
 
     $f = Html::normalize('<p><style> /* Styling */ body {color:red}</style></p>');
-    $this->assertEquals($f, '<p><style>
+    $this->assertEquals('<p><style>
 <!--/*--><![CDATA[/* ><!--*/
  /* Styling */ body {color:red}
 /*--><!]]>*/
-</style></p>', 'HTML corrector -- CDATA added to a style element.');
+</style></p>', $f, 'HTML corrector -- CDATA added to a style element.');
 
     $filtered_data = Html::normalize('<p><style>
 /*<![CDATA[*/
@@ -1054,7 +1054,7 @@ public function testHtmlCorrectorFilter() {
 body {color:red}
 /*]]>*/
 </style></p>');
-    $this->assertEquals($filtered_data, '<p><style>
+    $this->assertEquals('<p><style>
 <!--/*--><![CDATA[/* ><!--*/
 
 /*<![CDATA[*/
@@ -1063,7 +1063,7 @@ public function testHtmlCorrectorFilter() {
 /*]]]]><![CDATA[>*/
 
 /*--><!]]>*/
-</style></p>',
+</style></p>', $filtered_data,
       new FormattableMarkup('HTML corrector -- Existing cdata section @pattern_name properly escaped', ['@pattern_name' => '/*<![CDATA[*/'])
     );
 
@@ -1073,7 +1073,7 @@ public function testHtmlCorrectorFilter() {
   body {color:red}
   /*--><!]]>*/
 </style></p>');
-    $this->assertEquals($filtered_data, '<p><style>
+    $this->assertEquals('<p><style>
 <!--/*--><![CDATA[/* ><!--*/
 
   <!--/*--><![CDATA[/* ><!--*/
@@ -1082,7 +1082,7 @@ public function testHtmlCorrectorFilter() {
   /*--><!]]]]><![CDATA[>*/
 
 /*--><!]]>*/
-</style></p>',
+</style></p>', $filtered_data,
       new FormattableMarkup('HTML corrector -- Existing cdata section @pattern_name properly escaped', ['@pattern_name' => '<!--/*--><![CDATA[/* ><!--*/'])
     );
 
@@ -1091,7 +1091,7 @@ public function testHtmlCorrectorFilter() {
   alert("test");
 //--><!]]>
 </script></p>');
-    $this->assertEquals($filtered_data, '<p><script>
+    $this->assertEquals('<p><script>
 <!--//--><![CDATA[// ><!--
 
 <!--//--><![CDATA[// ><!--
@@ -1099,7 +1099,7 @@ public function testHtmlCorrectorFilter() {
 //--><!]]]]><![CDATA[>
 
 //--><!]]>
-</script></p>',
+</script></p>', $filtered_data,
       new FormattableMarkup('HTML corrector -- Existing cdata section @pattern_name properly escaped', ['@pattern_name' => '<!--//--><![CDATA[// ><!--'])
     );
 
@@ -1108,7 +1108,7 @@ public function testHtmlCorrectorFilter() {
   alert("test");
 // ]]>
 </script></p>');
-    $this->assertEquals($filtered_data, '<p><script>
+    $this->assertEquals('<p><script>
 <!--//--><![CDATA[// ><!--
 
 // <![CDATA[
@@ -1116,7 +1116,7 @@ public function testHtmlCorrectorFilter() {
 // ]]]]><![CDATA[>
 
 //--><!]]>
-</script></p>',
+</script></p>', $filtered_data,
       new FormattableMarkup('HTML corrector -- Existing cdata section @pattern_name properly escaped', ['@pattern_name' => '// <![CDATA['])
     );
 
diff --git a/web/core/modules/filter/tests/src/Kernel/Migrate/d6/FilterFormatPermissionTest.php b/web/core/modules/filter/tests/src/Kernel/Migrate/d6/FilterFormatPermissionTest.php
index 85e3bb198e..dcdf97b903 100644
--- a/web/core/modules/filter/tests/src/Kernel/Migrate/d6/FilterFormatPermissionTest.php
+++ b/web/core/modules/filter/tests/src/Kernel/Migrate/d6/FilterFormatPermissionTest.php
@@ -26,7 +26,7 @@ public function testConfigurableFilterFormat() {
     $reflected_config = new \ReflectionProperty($filterFormatPermissionMigration, 'configuration');
     $reflected_config->setAccessible(TRUE);
     $config = $reflected_config->getValue($filterFormatPermissionMigration);
-    $this->assertEquals($config['migration'], 'custom_filter_format');
+    $this->assertEquals('custom_filter_format', $config['migration']);
   }
 
 }
diff --git a/web/core/modules/forum/tests/src/Unit/Breadcrumb/ForumListingBreadcrumbBuilderTest.php b/web/core/modules/forum/tests/src/Unit/Breadcrumb/ForumListingBreadcrumbBuilderTest.php
index e7b19645f8..f353a284bb 100644
--- a/web/core/modules/forum/tests/src/Unit/Breadcrumb/ForumListingBreadcrumbBuilderTest.php
+++ b/web/core/modules/forum/tests/src/Unit/Breadcrumb/ForumListingBreadcrumbBuilderTest.php
@@ -142,12 +142,12 @@ public function testBuild() {
     $term2 = $prophecy->reveal();
 
     $term_storage = $this->getMockBuilder(TermStorageInterface::class)->getMock();
-    $term_storage->expects($this->at(0))
+    $term_storage->expects($this->exactly(2))
       ->method('loadAllParents')
-      ->will($this->returnValue([$term1]));
-    $term_storage->expects($this->at(1))
-      ->method('loadAllParents')
-      ->will($this->returnValue([$term1, $term2]));
+      ->willReturnOnConsecutiveCalls(
+        [$term1],
+        [$term1, $term2],
+      );
 
     // The root forum.
     $prophecy = $this->prophesize('Drupal\taxonomy\VocabularyInterface');
diff --git a/web/core/modules/forum/tests/src/Unit/Breadcrumb/ForumNodeBreadcrumbBuilderTest.php b/web/core/modules/forum/tests/src/Unit/Breadcrumb/ForumNodeBreadcrumbBuilderTest.php
index 2a65139582..17ce97ba07 100644
--- a/web/core/modules/forum/tests/src/Unit/Breadcrumb/ForumNodeBreadcrumbBuilderTest.php
+++ b/web/core/modules/forum/tests/src/Unit/Breadcrumb/ForumNodeBreadcrumbBuilderTest.php
@@ -153,12 +153,12 @@ public function testBuild() {
       ->disableOriginalConstructor()
       ->getMock();
     $term_storage = $this->getMockBuilder(TermStorageInterface::class)->getMock();
-    $term_storage->expects($this->at(0))
+    $term_storage->expects($this->exactly(2))
       ->method('loadAllParents')
-      ->will($this->returnValue([$term1]));
-    $term_storage->expects($this->at(1))
-      ->method('loadAllParents')
-      ->will($this->returnValue([$term1, $term2]));
+      ->willReturnOnConsecutiveCalls(
+        [$term1],
+        [$term1, $term2],
+      );
 
     $prophecy = $this->prophesize('Drupal\taxonomy\VocabularyInterface');
     $prophecy->label()->willReturn('Forums');
diff --git a/web/core/modules/hal/tests/src/Kernel/DenormalizeTest.php b/web/core/modules/hal/tests/src/Kernel/DenormalizeTest.php
index 9cc51dffde..7cfd17d0aa 100644
--- a/web/core/modules/hal/tests/src/Kernel/DenormalizeTest.php
+++ b/web/core/modules/hal/tests/src/Kernel/DenormalizeTest.php
@@ -157,7 +157,7 @@ public function testDenormalizeSerializedItem() {
   public function testDenormalizeInvalidCustomSerializedField() {
     $entity = EntitySerializedField::create(['serialized_long' => serialize(['Hello world!'])]);
     $normalized = $this->serializer->normalize($entity);
-    $this->assertEquals($normalized['serialized_long'][0]['value'], ['Hello world!']);
+    $this->assertEquals(['Hello world!'], $normalized['serialized_long'][0]['value']);
 
     $normalized['serialized_long'][0]['value'] = 'boo';
     $this->expectException(\LogicException::class);
diff --git a/web/core/modules/help_topics/help_topics/action.creating.html.twig b/web/core/modules/help_topics/help_topics/action.creating.html.twig
new file mode 100644
index 0000000000..d4f96168fd
--- /dev/null
+++ b/web/core/modules/help_topics/help_topics/action.creating.html.twig
@@ -0,0 +1,28 @@
+---
+label: 'Creating an advanced action'
+related:
+  - action.overview
+  - views_ui.bulk_operations
+---
+{% set actions_link_text %}
+  {% trans %}Actions{% endtrans %}
+{% endset %}
+{% set actions = render_var(help_route_link(actions_link_text, 'entity.action.collection')) %}
+{% set action_permissions_link_text %}
+  {% trans %}Administer actions{% endtrans %}
+{% endset %}
+{% set action_permissions = render_var(help_route_link(action_permissions_link_text, 'user.admin_permissions', {}, {'fragment': 'module-action'})) %}
+{% set action_overview = render_var(help_topic_link('action.overview')) %}
+<h2>{% trans %}Goal{% endtrans %}</h2>
+<p>{% trans %}Create an advanced action. You can, for example, create an action to change the author of multiple content items. See {{ action_overview }} for more about actions.{% endtrans %}</p>
+<h2>{% trans %}Who can create actions?{% endtrans %}</h2>
+<p>{% trans %}Users with the <em>{{ action_permissions }}</em> permission (typically administrators) can create actions.{% endtrans %}</p>
+<h2>{% trans %}Steps{% endtrans %}</h2>
+<ol>
+  <li>{% trans %}In the <em>Manage</em> administrative menu, navigate to <em>Configuration</em> &gt; <em>System</em> &gt; <em>{{ actions }}</em>. A list of all actions is shown.{% endtrans %}</li>
+  <li>{% trans %}Choose an advanced action from the dropdown and click <em>Create</em>.{% endtrans %}</li>
+  <li>{% trans %}Enter a name for the action in the <em>Label</em> field. This label will be visible for the user.{% endtrans %}</li>
+  <li>{% trans %}Configure any of the other available options. These will depend on the kind of action that you have chosen.{% endtrans %}</li>
+  <li>{% trans %}Click <em>Save</em>. You will be returned to the list of actions, with your new action added to the list.{% endtrans %}</li>
+  <li>{% trans %}To edit an action you have previously created, click <em>Configure</em> in the <em>Operations</em> drop-down list. To delete an action you have previously created, click <em>Delete</em> in the <em>Operations</em> drop-down list.{% endtrans %}</li>
+</ol>
diff --git a/web/core/modules/help_topics/help_topics/action.overview.html.twig b/web/core/modules/help_topics/help_topics/action.overview.html.twig
new file mode 100644
index 0000000000..d3c5642ba3
--- /dev/null
+++ b/web/core/modules/help_topics/help_topics/action.overview.html.twig
@@ -0,0 +1,25 @@
+---
+label: 'Configuring actions'
+top_level: true
+related:
+  - views.overview
+  - views_ui.bulk_operations
+---
+{% set actions_link_text %}
+  {% trans %}Actions page{% endtrans %}
+{% endset %}
+{% set actions_page = render_var(help_route_link(actions_link_text, 'entity.action.collection')) %}
+<h2>{% trans %}What are actions?{% endtrans %}</h2>
+<p>{% trans %}Actions are module-defined tasks that can be executed on the site; for example, unpublishing content, sending an email message, or blocking a user.{% endtrans %}</p>
+<h2>{% trans %}What are simple actions?{% endtrans %}</h2>
+<p>{% trans %}Simple actions do not require configuration. They are automatically available to be executed, and are always listed as available on the {{ actions_page }}.{% endtrans %}</p>
+<h2>{% trans %}What are advanced actions?{% endtrans %}</h2>
+<p>{% trans %}Advanced actions require configuration. Before they are available for listing and execution, they need to be created and configured. For example, for an action that sends e-mail, you would need to configure the e-mail address.{% endtrans %}</p>
+<h2>{% trans %}How are actions executed?{% endtrans %}</h2>
+<p>{% trans %}In the core software, actions can be executed through a <em>bulk operations form</em> added to a view; if you have the core Views module installed, see the related topic "Managing content listings (views)" for more information about views and bulk operations.{% endtrans %}</p>
+<h2>{% trans %}Configuring actions overview{% endtrans %}</h2>
+<p>{% trans %}The core Actions module provides a user interface for listing and configuring actions. The core Views UI module provides a user interface for creating views, which may include bulk operations forms for executing actions. See the related topics listed below for specific tasks.{% endtrans %}</p>
+<h2>{% trans %}Additional resources{% endtrans %}</h2>
+<ul>
+  <li><a href="https://www.drupal.org/documentation/modules/action">{% trans %}Online documentation for the Action module{% endtrans %}</a></li>
+</ul>
diff --git a/web/core/modules/help_topics/help_topics/comment.configuring.html.twig b/web/core/modules/help_topics/help_topics/comment.configuring.html.twig
new file mode 100644
index 0000000000..2fd76b831d
--- /dev/null
+++ b/web/core/modules/help_topics/help_topics/comment.configuring.html.twig
@@ -0,0 +1,43 @@
+---
+label: 'Configuring comments'
+related:
+  - comment.overview
+  - comment.creating_type
+  - comment.disabling
+  - field_ui.add_field
+---
+{% set comment_permissions_link_text %}
+{% trans %}Administer comments and comment settings{% endtrans %}
+{% endset %}
+{% set comment_permissions_link = render_var(help_route_link(comment_permissions_link_text, 'user.admin_permissions', {}, {'fragment': 'module-comment'})) %}
+{% set content_structure_topic = render_var(help_topic_link('core.content_structure')) %}
+{% set comment_type_topic = render_var(help_topic_link('comment.creating_type')) %}
+<h2>{% trans %}Goal{% endtrans %}</h2>
+<p>{% trans %}Configure a content entity type/subtype to allow commenting, using a comment type that you have configured. See {{ content_structure_topic }} for more about content entities and fields, and {{ comment_type_topic }} to configure a comment type.{% endtrans %}</p>
+<h2>{% trans %}Who can configure comments?{% endtrans %}</h2>
+<p>{% trans %}In order to follow these steps, the Field UI module must be installed. You'll need the Comment module's <em>{{ comment_permissions_link }}</em> permission, in order to change comment settings for a comment field. You'll also need to have the appropriate permission for adding fields to the entity type or subtype that the comments are attached to. For example, to add a comment field to content items provided by the Node module, you would need the Node module's <em>Administer content types</em> permission.{% endtrans %}</p>
+<h2>{% trans %}Steps{% endtrans %}</h2>
+<ol>
+  <li>{% trans %}Follow the steps in the related <em>Adding a field to an entity sub-type</em> topic to add a field of type <em>Comments</em> to the desired entity type or sub-type.{% endtrans %}</li>
+  <li>{% trans %}On the first field settings page, choose the <em>Comment type</em> to use for this entity type or sub-type. You'll also notice that the <em>Allowed number of values</em> field cannot be changed for comment fields.{% endtrans %}</li>
+  <li>{% trans %}On the next field settings page, enter the desired settings for the comment field:{% endtrans %}
+    <ul>
+      <li>{% trans %}<em>Threading</em>: whether or not the comments are collected by threads, with people able to reply to particular comments instead of to the content entity itself.{% endtrans %}</li>
+      <li>{% trans %}<em>Comments per page</em>: the maximum number of comments displayed on one page (a pager will be added if you exceed this limit).{% endtrans %}</li>
+      <li>{% trans %}<em>Anonymous commenting</em>: whether or not anonymous commenters are allowed or required to leave contact information with their comments (only applies if anonymous users have permission to post comments).{% endtrans %}</li>
+      <li>{% trans %}<em>Show reply form on the same page as comments</em>: whether the comment reply form is displayed on the same page as the comments. If this is not selected, clicking <em>Reply</em> will open a new page with the reply form.{% endtrans %}</li>
+      <li>{% trans %}<em>Preview comments</em>: whether previewing comments before submission is <em>Required</em>, <em>Optional</em>, or <em>Disabled</em>.{% endtrans %}</li>
+      <li>{% trans %}<em>Default value</em>: each individual entity has its own comment settings, but here you can set defaults for the comment settings for this entity type or subtype. The comment settings values are:{% endtrans %}
+        <ul>
+          <li>{% trans %}<em>Open</em>: comments are allowed.{% endtrans %}</li>
+          <li>{% trans %}<em>Closed</em>: past comments remain visible, but no new comments are allowed.{% endtrans %}</li>
+          <li>{% trans %}<em>Hidden</em>: past comments are hidden, and no new comments are allowed.{% endtrans %}</li>
+        </ul>
+      </li>
+    </ul>
+  </li>
+</ol>
+<h2>{% trans %}Additional resources{% endtrans %}</h2>
+<ul>
+  <li><a href="https://www.drupal.org/docs/8/core/modules/comment/administering-a-content-types-comment-settings">{% trans %}Online documentation for content comment settings{% endtrans %}</a></li>
+</ul>
diff --git a/web/core/modules/help_topics/help_topics/comment.creating_type.html.twig b/web/core/modules/help_topics/help_topics/comment.creating_type.html.twig
new file mode 100644
index 0000000000..0d1e07ff62
--- /dev/null
+++ b/web/core/modules/help_topics/help_topics/comment.creating_type.html.twig
@@ -0,0 +1,32 @@
+---
+label: 'Creating a comment type'
+related:
+  - field_ui.add_field
+  - field_ui.manage_display
+  - field_ui.manage_form
+  - comment.overview
+  - comment.configuring
+---
+{% set comment_types_link_text %}
+  {% trans %}Comment types{% endtrans %}
+{% endset %}
+{% set comment_types_link = render_var(help_route_link(comment_types_link_text, 'entity.comment_type.collection')) %}
+{% set comment_permissions_link_text %}
+  {% trans %}Administer comment types and settings{% endtrans %}
+{% endset %}
+{% set comment_permissions_link = render_var(help_route_link(comment_permissions_link_text, 'user.admin_permissions', {}, {'fragment': 'module-comment'})) %}
+{% set comment_overview_topic = render_var(help_topic_link('comment.overview')) %}
+{% set content_structure_topic = render_var(help_topic_link('core.content_structure')) %}
+<h2>{% trans %}Goal{% endtrans %}</h2>
+<p>{% trans %}Create a new comment type. See {{ comment_overview_topic }} for information about comments and comment types.{% endtrans %}</p>
+<h2>{% trans %}Who can create a comment type?{% endtrans %}</h2>
+<p>{% trans %}Users with the <em>{{ comment_permissions_link }}</em> permission (typically administrators) can create comment types.{% endtrans %}</p>
+<h2>{% trans %}Steps{% endtrans %}</h2>
+<ol>
+  <li>{% trans %}In the <em>Manage</em> administrative menu, navigate to <em>Structure</em> &gt; <em>{{ comment_types_link }}</em>.{% endtrans %}</li>
+  <li>{% trans %}Click <em>Add comment type</em>.{% endtrans %}</li>
+  <li>{% trans %}In the <em>Label</em> field, enter a name for the comment type, which is how it will be listed in the administrative interface.{% endtrans %}</li>
+  <li>{% trans %}In the <em>Target entity type</em> field, select the entity type to be commented on. See {{ content_structure_topic }} for more about content entities and fields.{% endtrans %}</li>
+  <li>{% trans %}Click <em>Save</em>. The comment type will be created.{% endtrans %}</li>
+  <li>{% trans %}Optionally, if you have the core Field UI module installed you can follow the steps in the related topics to add fields to the new comment type, set up the editing form, and configure the display.{% endtrans %}</li>
+</ol>
diff --git a/web/core/modules/help_topics/help_topics/comment.disabling.html.twig b/web/core/modules/help_topics/help_topics/comment.disabling.html.twig
new file mode 100644
index 0000000000..77ec431fce
--- /dev/null
+++ b/web/core/modules/help_topics/help_topics/comment.disabling.html.twig
@@ -0,0 +1,28 @@
+---
+label: 'Disabling comments'
+related:
+  - comment.overview
+  - comment.configuring
+---
+{% set comment_permissions_text %}
+{% trans %}Administer comments and comment settings{% endtrans %}
+{% endset %}
+{% set comment_permissions_link = render_var(help_route_link(comment_permissions_text, 'user.admin_permissions', {}, {'fragment': 'module-comment'})) %}
+{% set comment_config_topic = render_var(help_topic_link('comment.configuring')) %}
+{% set content_structure_topic = render_var(help_topic_link('core.content_structure')) %}
+<h2>{% trans %}Goal{% endtrans %}</h2>
+<p>{% trans %}Turn off commenting for a particular entity (see {{ content_structure_topic }} for more about content entities and fields). Note that if you want to turn off commenting for all entities of an entity type or subtype, you will need to edit the field settings for the comment field; see {{ comment_config_topic }} for more about configuring the comment field.{% endtrans %}</p>
+<h2>{% trans %}Who can disable comments?{% endtrans %}</h2>
+<p>{% trans %}You will need the <em>{{ comment_permissions_link }}</em> permission in order to disable commenting. You will also need permission to edit the entity that the comments are on.{% endtrans %}</p>
+<h2>{% trans %}Steps{% endtrans %}</h2>
+<ol>
+  <li>{% trans %}Find the entity you want to disable comments for, and edit it. For example, to turn off comments on a content item, you could find it by navigating in the <em>Manage</em> administrative menu to <em>Content</em>, filtering to find the content item, and clicking <em>Edit</em>.{% endtrans %}</li>
+  <li>{% trans %}Under <em>Comment settings</em>, select the desired comment setting:{% endtrans %}
+    <ul>
+      <li>{% trans %}<em>Open</em>: comments are allowed.{% endtrans %}</li>
+      <li>{% trans %}<em>Closed</em>: past comments remain visible, but no new comments are allowed.{% endtrans %}</li>
+      <li>{% trans %}<em>Hidden</em>: past comments are hidden, and no new comments are allowed.{% endtrans %}</li>
+    </ul>
+  </li>
+  <li>{% trans %}Save the entity.{% endtrans %}</li>
+</ol>
diff --git a/web/core/modules/help_topics/help_topics/comment.moderating.html.twig b/web/core/modules/help_topics/help_topics/comment.moderating.html.twig
new file mode 100644
index 0000000000..6013c033fd
--- /dev/null
+++ b/web/core/modules/help_topics/help_topics/comment.moderating.html.twig
@@ -0,0 +1,34 @@
+---
+label: 'Moderating comments'
+related:
+  - comment.overview
+  - comment.configuring
+  - comment.disabling
+---
+{% set comment_unpublished_link_text %}
+  {% trans %}Unapproved comments{% endtrans %}
+{% endset %}
+{% set comment_unpublished_link = render_var(help_route_link(comment_unpublished_link_text, 'comment.admin_approval')) %}
+{% set comment_published_link_text %}
+  {% trans %}Comments{% endtrans %}
+{% endset %}
+{% set comment_published_link = render_var(help_route_link(comment_published_link_text, 'comment.admin')) %}
+{% set comment_permissions_link_text %}
+  {% trans %}Administer comments and comment settings{% endtrans %}
+{% endset %}
+{% set comment_permissions_link = render_var(help_route_link(comment_permissions_link_text, 'user.admin_permissions', {}, {'fragment': 'module-comment'})) %}
+<h2>{% trans %}Goal{% endtrans %}</h2>
+<p>{% trans %}Decide which comments are shown on the website.{% endtrans %}</p>
+<h2>{% trans %}Who can moderate comments?{% endtrans %}</h2>
+<p>{% trans %}Users with the <em>{{ comment_permissions_link }}</em> permission (typically administrators) can moderate comments. You will also need the <em>Access the Content Overview page</em> permission from the Node module (if it is installed) to navigate to the comment management page.{% endtrans %}</p>
+<h2>{% trans %}Steps{% endtrans %}</h2>
+<ol>
+  <li>{% trans %}In the <em>Manage</em> administrative menu, navigate to <em>Content</em> &gt; <em>{{ comment_published_link }}</em>. A list of all comments is shown.{% endtrans %}</li>
+  <li>{% trans %}To unpublish comments, select one or more comments by checking the boxes on the left side (right side in right-to-left languages). Then select <em>Unpublish comment</em> from the <em>Action</em> select list and click <em>Apply to selected items</em>. If you select the <em>Delete comment</em> action, you can instead delete the unwanted  comments.{% endtrans %}</li>
+  <li>{% trans %}To change the content of a comment click <em>Edit</em> from the dropdown button for a particular comment.{% endtrans %}</li>
+  <li>{% trans %}To publish comments that are not yet visible on the website, navigate to the <em>{{ comment_unpublished_link }}</em> tab. Select one or more comments by checking the boxes on the left side (right side in right-to-left languages). Then select <em>Publish comment</em> from the <em>Action</em> select list and click <em>Apply to selected items</em>.{% endtrans %}</li>
+</ol>
+<h2>{% trans %}Additional resources{% endtrans %}</h2>
+<ul>
+  <li><a href="https://www.drupal.org/docs/8/core/modules/comment/administering-and-approving-comments">{% trans %}Online documentation for moderating comments{% endtrans %}</a></li>
+</ul>
diff --git a/web/core/modules/help_topics/help_topics/comment.overview.html.twig b/web/core/modules/help_topics/help_topics/comment.overview.html.twig
new file mode 100644
index 0000000000..660d3770e1
--- /dev/null
+++ b/web/core/modules/help_topics/help_topics/comment.overview.html.twig
@@ -0,0 +1,29 @@
+---
+label: 'Managing comments'
+top_level: true
+related:
+  - comment.moderating
+  - comment.configuring
+  - comment.creating_type
+  - comment.disabling
+  - field_ui.add_field
+  - field_ui.manage_display
+  - field_ui.manage_form
+---
+{% set content_structure_topic = render_var(help_topic_link('core.content_structure')) %}
+{% set users_overview_topic = render_var(help_topic_link('user.overview')) %}
+<h2>{% trans %}What is a comment?{% endtrans %}</h2>
+<p>{% trans %}A comment is a piece of content, typically posted by a website visitor, which provides discussion or commentary on other content like forum topics, blog posts, and news articles. Comments are a type of content entity, and can have fields that store text, HTML markup, and other data. Comments are attached to other content entities via Comment fields. See {{ content_structure_topic }} for more about content entities and fields.{% endtrans %}</p>
+<h2>{% trans %}What is a comment type?{% endtrans %}</h2>
+<p>{% trans %}Comments are divided into <em>comment types</em>, which are the entity sub-types for the comment entity type. Each comment type has its own fields and its own form and display settings; each type can be used to comment on a single entity type. You can set up different comment types for different commenting purposes on your web site; for example, you might set up a comment type for recipes that has fields "How did it taste?" and "Did the instructions work?", and another comment type for blog entries that has only a generic comment body field.{% endtrans %}</p>
+<h2>{% trans %}What is moderation?{% endtrans %}</h2>
+<p>{% trans %}<em>Moderation</em> is a workflow where comments posted by some users on your site are verified before being published, to prevent spam and other bad behavior. The core software provides basic moderation functionality: you can configure permissions so that new comments posted by some user roles start as unpublished until a user with a different role reviews and publishes them. Contributed modules provide additional moderation and spam-reduction functionality, such as requiring untrusted users pass a CAPTCHA test before submitting comments and letting community members flag comments as possible spam. See {{ users_overview_topic }} for more about users, permissions, and roles.{% endtrans %}</p>
+<h2>{% trans %}Overview of managing comments{% endtrans %}</h2>
+<p>{% trans %}The core Comment module provides the following functionality:{% endtrans %}</p>
+<ul>
+  <li>{% trans %}Posting comments{% endtrans %}</li>
+  <li>{% trans %}Creating comment types; the core Field UI module allows you to attach fields to comment types and attach comment reference fields to other entities so that people can comment on them.{% endtrans %}</li>
+  <li>{% trans %}Configuring commenting{% endtrans %}</li>
+  <li>{% trans %}Moderating comments as discussed above{% endtrans %}</li>
+</ul>
+<p>{% trans %}See the related topics listed below for specific tasks.{% endtrans %}</p>
diff --git a/web/core/modules/help_topics/help_topics/core.quick_edit.html.twig b/web/core/modules/help_topics/help_topics/core.quick_edit.html.twig
new file mode 100644
index 0000000000..21d22d55dc
--- /dev/null
+++ b/web/core/modules/help_topics/help_topics/core.quick_edit.html.twig
@@ -0,0 +1,19 @@
+---
+label: 'Using in-line (quick) editing'
+related:
+  - core.ui_components
+---
+<h2>{% trans %}Goal{% endtrans %}</h2>
+<p>{% trans %}Edit content or settings in place.{% endtrans %}</p>
+<h2>{% trans %}What is quick editing?{% endtrans %}</h2>
+<p>{% trans %}Quick editing is editing either content or settings inline. Content quick editing is provided by the core Quick Edit module, and settings quick editing is provided by the core Settings Tray module; both of them require the core Contextual Links module in order to expose the links that let you edit in place.{% endtrans %}</p>
+<h2>{% trans %}Who can edit content and settings in place?{% endtrans %}</h2>
+<p>{% trans %}In order to follow these steps to edit content in place, the core Quick Edit module must be installed; to edit settings, the core Settings Tray module must be installed. Also, either the core Toolbar module or a contributed replacement must be installed. You will need to have <em>Use contextual links</em> permission, as well as permission to edit the particular content or settings.{% endtrans %}</p>
+<h2>{% trans %}Steps{% endtrans %}</h2>
+<ol>
+  <li>{% trans %}Find and visit a page on your site that has either content or settings that you would like to edit.{% endtrans %}</li>
+  <li>{% trans %}Click the contextual links <em>Edit</em> button on the toolbar (in most themes, it looks like a pencil). Contextual <em>Edit</em> links with the same icon will appear all over your page.{% endtrans %}</li>
+  <li>{% trans %}Find the contextual link for the part of the page you want to edit. For example, if you want to edit the settings for a block, the link should be in the top-right corner of the block, or top-left for right-to-left languages.{% endtrans %}</li>
+  <li>{% trans %}Click the link to open the contextual links menu, and click <em>Quick edit</em>. An editing form for the settings or content should appear on the page.{% endtrans %}</li>
+  <li>{% trans %}Make your edits and submit the form.{% endtrans %}</li>
+</ol>
diff --git a/web/core/modules/help_topics/help_topics/core.ui_accessibility.html.twig b/web/core/modules/help_topics/help_topics/core.ui_accessibility.html.twig
index 083454fd22..b848f7b346 100644
--- a/web/core/modules/help_topics/help_topics/core.ui_accessibility.html.twig
+++ b/web/core/modules/help_topics/help_topics/core.ui_accessibility.html.twig
@@ -4,8 +4,10 @@ related:
   - core.ui_components
 ---
 <h2>{% trans %}Overview of accessibility{% endtrans %}</h2>
-<p>{% trans %}The core administrative interface has built-in compliance with many accessibility standards, so that most pages are accessible to most users in their default state. However, certain pages become more accessible to some users through the use of a non-default interface. These replacement interfaces include:{% endtrans %}</p>
+<p>{% trans %}The core administrative interface has built-in compliance with many accessibility standards so that most pages are accessible to most users in their default state. However, certain pages become more accessible to some users through the use of a non-default or improved interface. These interfaces include:{% endtrans %}</p>
 <dl>
   <dt>{% trans %}Disabling drag-and-drop functionality{% endtrans %}</dt>
   <dd>{% trans %}The default drag-and-drop user interface for ordering tables in the administrative interface presents a challenge for some users, including keyboard-only users and users of screen readers and other assistive technology. The drag-and-drop interface can be disabled in a table by clicking a link labeled <em>Show row weights</em> above the table. The replacement interface allows users to order the table by choosing numerical weights (with increasing numbers) instead of dragging table rows.{% endtrans %}</dd>
+  <dt>{% trans %}Enabling inline form errors{% endtrans %}</dt>
+  <dd>{% trans %}Errors that occur when you submit a form, such as not filling in a required field, are sometimes difficult for users to understand and locate. In order to make these errors easier to find, the best practice is to put a summary of the errors at the top of the form page. To make them easier to understand, the best practice is to display error messages with the form fields they are related to. Both of these practices are implemented by the core Inline Form Errors module.{% endtrans %}</dd>
 </dl>
diff --git a/web/core/modules/help_topics/help_topics/core.ui_components.html.twig b/web/core/modules/help_topics/help_topics/core.ui_components.html.twig
index f8aab0dd46..503b0e91f5 100644
--- a/web/core/modules/help_topics/help_topics/core.ui_components.html.twig
+++ b/web/core/modules/help_topics/help_topics/core.ui_components.html.twig
@@ -4,15 +4,31 @@ top_level: true
 related:
   - block.overview
 ---
-<h2>{% trans %}Administrative interface overview{% endtrans %}</h2>
-<p>{% trans %}The administrative interface has several components:{% endtrans %}</p>
+{% set accessibility_topic = render_var(help_topic_link('core.ui_accessibility')) %}
+{% set quick_edit_topic = render_var(help_topic_link('core.quick_edit')) %}
+{% set admin_link = render_var(help_route_link('/admin', 'system.admin')) %}
+<h2>{% trans %}What administrative interface components are available?{% endtrans %}</h2>
+<p>{% trans %}The following administrative interface components are provided by Drupal core and its modules (some contributed modules offer additional functionality):{% endtrans %}</p>
 <ul>
-  <li>{% trans %}Accessibility features, to enable all users to perform administrative tasks.{% endtrans %}</li>
+  <li>{% trans %}Accessibility features, to enable all users to perform administrative tasks. See {{ accessibility_topic }} for more information.{% endtrans %}</li>
   <li>{% trans %}A menu system, which you can navigate to find pages for administrative tasks. The core Toolbar module displays this menu on the top or left side of the page (right side in right-to-left languages). There are also contributed module replacements for the core Toolbar module, with additional features, such as the <a href="https://www.drupal.org/project/admin_toolbar">Admin Toolbar module</a>.{% endtrans %}</li>
   <li>{% trans %}The core Shortcuts module enhances the toolbar with a configurable list of links to commonly-used tasks.{% endtrans %}</li>
   <li>{% trans %}If you install the core Contextual Links module, non-administrative pages will contain links leading to related administrative tasks.{% endtrans %}</li>
+  <li>{% trans %}In-place or <em>quick</em> editing. In-place editing of content is provided by the core Quick Edit module, and in-place editing of configuration is provided by the core Settings Tray module. See {{ quick_edit_topic }} for more information.{% endtrans %}</li>
   <li>{% trans %}The core Help module displays help topics, and provides a Help block that can be placed on administrative pages to provide an overview of their functionality.{% endtrans %}</li>
   <li>{% trans %}The core Tour module allows modules to provide interactive tours of administrative pages for more detailed help.{% endtrans %}</li>
 </ul>
-
-<p>{% trans %}See the related topics listed below for specific tasks.{% endtrans %}</p>
+<h2>{% trans %}What are the sections of the administrative menu?{% endtrans %}</h2>
+<p>{% trans %}The administrative menu, which you can navigate by visiting <em>{{ admin_link }}</em> on your site or by using an administrative toolbar, has the following sections (some may not be available, depending on which modules are currently installed on your site, and your permissions):{% endtrans %}</p>
+<ul>
+  <li>{% trans %}<strong>Content:</strong> Find, manage, and create new pages; manage comments and files.{% endtrans %}</li>
+  <li>{% trans %}<strong>Structure:</strong> Place and edit blocks, set up content types and fields, configure menus, administer taxonomy, and configure some contributed modules.{% endtrans %}</li>
+  <li>{% trans %}<strong>Appearance:</strong> Switch between themes, install themes, and update existing themes.{% endtrans %}</li>
+  <li>{% trans %}<strong>Extend:</strong> Update, install, and uninstall modules.{% endtrans %}</li>
+  <li>{% trans %}<strong>Configuration:</strong> Configure the settings for various site functionality, including some contributed modules.{% endtrans %}</li>
+  <li>{% trans %}<strong>People:</strong> Manage user accounts and permissions.{% endtrans %}</li>
+  <li>{% trans %}<strong>Reports:</strong> Display information about site security, necessary updates, and site activity.{% endtrans %}</li>
+  <li>{% trans %}<strong>Help:</strong> Get help on using the administrative interface.{% endtrans %}</li>
+</ul>
+<h2>{% trans %}Administrative interface overview{% endtrans %}</h2>
+<p>{% trans %}Install the core modules mentioned above to use the corresponding aspect of the administrative interface. See the related topics listed below for more details on some aspects of the administrative interface.{% endtrans %}</p>
diff --git a/web/core/modules/help_topics/help_topics/node.creating_content.html.twig b/web/core/modules/help_topics/help_topics/node.creating_content.html.twig
new file mode 100644
index 0000000000..ea28358ebb
--- /dev/null
+++ b/web/core/modules/help_topics/help_topics/node.creating_content.html.twig
@@ -0,0 +1,36 @@
+---
+label: 'Creating a content item'
+related:
+  - node.overview
+  - node.creating_type
+  - path.creating_alias
+---
+{% set content_link_text %}
+  {% trans %}Content{% endtrans %}
+{% endset %}
+{% set content_link = render_var(help_route_link(content_link_text, 'system.admin_content')) %}
+{% set content_permissions_link_text %}
+  {% trans %}Access the Content overview page{% endtrans %}
+{% endset %}
+{% set content_permissions_link = render_var(help_route_link(content_permissions_link_text, 'user.admin_permissions', {}, {'fragment': 'module-node'})) %}
+{% set content_overview_topic = render_var(help_topic_link('node.overview')) %}
+<h2>{% trans %}Goal{% endtrans %}</h2>
+<p>{% trans %}Create and publish a content item. See {{ content_overview_topic }} for more about content types and content items.{% endtrans %}</p>
+<h2>{% trans %}Who can create content?{% endtrans %}</h2>
+<p>{% trans %}Users with the <em>{{ content_permissions_link }}</em> permission can visit the <em>Content</em> page as described in this topic. Each content type has its own create permissions. For example, to create content of type Article, a user would need the Article: Create new content permission. In addition, users with the <em>Bypass content access control</em> or <em>Administer content</em> permission can create content items of all types. Some contributed modules change the permission structure for creating content.{% endtrans %}</p>
+<h2>{% trans %}Steps{% endtrans %}</h2>
+<ol>
+  <li>{% trans %}In the <em>Manage</em> administrative menu, navigate to <em>{{ content_link }}</em>.{% endtrans %}</li>
+  <li>{% trans %}Click <em>Add content</em>.{% endtrans %}</li>
+  <li>{% trans %}If there is more than one content type defined on your site that you have permission to create, click the name of the type of content you want to create.{% endtrans %}</li>
+  <li>{% trans %}On the content edit form, enter the <em>Title</em> of your content, which will show as the page title when the content item is displayed on a page, and also as the label for the content item in administration screens.{% endtrans %}</li>
+  <li>{% trans %}Fill in the other fields shown on the edit form for this specific content type.{% endtrans %}</li>
+  <li>{% trans %}Leave the <em>Published</em> field checked to publish the content immediately, or uncheck it to make it unpublished. Unpublished content is generally not shown to non-administrative site users.{% endtrans %}</li>
+  <li>{% trans %}Optionally, click <em>Preview</em> to preview the content.{% endtrans %}</li>
+  <li>{% trans %}Click <em>Save</em>. You will see the content displayed on a page.{% endtrans %}</li>
+</ol>
+<h2>{% trans %}Additional resources{% endtrans %}</h2>
+<ul>
+  <li><a href="https://www.drupal.org/docs/user_guide/en/content-chapter.html">{% trans %}User Guide: Basic page management{% endtrans %}</a></li>
+  <li><a href="https://www.drupal.org/docs/user_guide/en/content-create.html">{% trans %}User Guide: Creating a content item{% endtrans %}</a></li>
+</ul>
diff --git a/web/core/modules/help_topics/help_topics/node.creating_type.html.twig b/web/core/modules/help_topics/help_topics/node.creating_type.html.twig
new file mode 100644
index 0000000000..424b9c8f5f
--- /dev/null
+++ b/web/core/modules/help_topics/help_topics/node.creating_type.html.twig
@@ -0,0 +1,36 @@
+---
+label: 'Creating a content type'
+related:
+  - node.overview
+  - core.content_structure
+  - field_ui.add_field
+  - field_ui.manage_display
+  - field_ui.manage_form
+---
+{% set content_permissions_link_text %}
+  {% trans %}Administer content types{% endtrans %}
+{% endset %}
+{% set content_permissions_link = render_var(help_route_link(content_permissions_link_text, 'user.admin_permissions', {}, {'fragment': 'module-node'})) %}
+{% set content_types_link_text %}
+  {% trans %}Content types{% endtrans %}
+{% endset %}
+{% set content_types_link = render_var(help_route_link(content_types_link_text, 'entity.node_type.collection')) %}
+{% set content_overview_topic = render_var(help_topic_link('node.overview')) %}
+<h2>{% trans %}Goal{% endtrans %}</h2>
+<p>{% trans %}Create a new content type. See {{ content_overview_topic }} for more about content types.{% endtrans %}</p>
+<h2>{% trans %}Who can create a content type?{% endtrans %}</h2>
+<p>{% trans %}Users with the <em>{{ content_permissions_link }}</em> permission (typically administrators) can create new content types.{% endtrans %}</p>
+<h2>{% trans %}Steps{% endtrans %}</h2>
+<ol>
+  <li>{% trans %}In the <em>Manage</em> administrative menu, navigate to <em>Structure</em> &gt; <em>{{ content_types_link }}</em>.{% endtrans %}</li>
+  <li>{% trans %}Click <em>Add content type.</em>{% endtrans %}</li>
+  <li>{% trans %}In the <em>Name</em> field, enter a name for the content type, which is how it will be listed in the administrative interface.{% endtrans %}</li>
+  <li>{% trans %}Optionally, enter a <em>Description</em> for the content type. You may also want to adjust some of the settings in the vertical tabs section of the edit page.{% endtrans %}</li>
+  <li>{% trans %}Click <em>Save and manage fields</em>. Your content type will be created, and assuming you have the core Field UI module installed, you will be taken to the <em>Manage fields</em> page for the content type. (If you do not have the core Field UI module installed, the button will say <em>Save</em> instead.){% endtrans %}</li>
+  <li>{% trans %}If you have the core Field UI module installed, follow the steps in the related topics to add fields to the new content type, set up the editing form, and configure the display.{% endtrans %}</li>
+</ol>
+<h2>{% trans %}Additional resources{% endtrans %}</h2>
+<ul>
+  <li><a href="https://www.drupal.org/docs/user_guide/en/structure-content-type.html">{% trans %}User Guide: Adding a content type{% endtrans %}</a></li>
+  <li><a href="https://www.drupal.org/docs/user_guide/en/content-structure-chapter.html">{% trans %}User Guide: Setting up content structure{% endtrans %}</a></li>
+</ul>
diff --git a/web/core/modules/help_topics/help_topics/node.editing.html.twig b/web/core/modules/help_topics/help_topics/node.editing.html.twig
new file mode 100644
index 0000000000..2c0351aa0d
--- /dev/null
+++ b/web/core/modules/help_topics/help_topics/node.editing.html.twig
@@ -0,0 +1,39 @@
+---
+label: 'Editing a content item'
+related:
+  - node.overview
+  - node.creating_content
+---
+{% set content_link_text %}
+  {% trans %}Content{% endtrans %}
+{% endset %}
+{% set content_link = render_var(help_route_link(content_link_text, 'system.admin_content')) %}
+{% set content_permissions_link_text %}
+  {% trans %}Access the Content overview page{% endtrans %}
+{% endset %}
+{% set content_permissions_link = render_var(help_route_link(content_permissions_link_text, 'user.admin_permissions', {}, {'fragment': 'module-node'})) %}
+{% set node_overview_topic = render_var(help_topic_link('node.overview')) %}
+<h2>{% trans %}Goal{% endtrans %}</h2>
+<p>{% trans %}Find a content item and edit it, or update a group of content items in bulk. See {{ node_overview_topic }} for more about content types and content items.{% endtrans %}</p>
+<h2>{% trans %}Who can find and edit content?{% endtrans %}</h2>
+<p>{% trans %}Users with the <em>{{ content_permissions_link }}</em> permission can use the <em>Content</em> page to find content. Each content type has its own edit permissions. For example, to edit content of type Article, a user would need the <em>Article: Edit own content</em> permission to edit an article they created, or the <em>Article: Edit any content</em> permission to edit an article someone else created. In addition, users with the <em>Bypass content access control</em> or <em>Administer content</em> permission can edit content items of all types. Some contributed modules change the permission structure for editing content.{% endtrans %}</p>
+<h2>{% trans %}Steps{% endtrans %}</h2>
+<ol>
+  <li>{% trans %}In the <em>Manage</em> administrative menu, navigate to <em>{{ content_link }}</em>.{% endtrans %}</li>
+  <li>{% trans %}Optionally, use filters to reduce the list of content items shown:{% endtrans %}
+    <ul>
+      <li>{% trans %}<em>Title</em>: key word(s) from the title{% endtrans %}</li>
+      <li>{% trans %}<em>Content type</em>{% endtrans %}</li>
+      <li>{% trans %}<em>Published status</em>{% endtrans %}</li>
+      <li>{% trans %}<em>Language</em>{% endtrans %}</li>
+    </ul>
+    {% trans %}If you enter or select filter values, click <em>Filter</em> to apply the filters.{% endtrans %}</li>
+  <li>{% trans %}Optionally, sort the list by clicking a column header. Click again to reverse the order.{% endtrans %}</li>
+  <li>{% trans %}To edit the title or other field values for one content item, click <em>Edit</em> in the row of the content item. Update the values and click <em>Save</em>.{% endtrans %}</li>
+  <li>{% trans %}A few types of edits can be done in bulk to multiple content items. For example, to publish several unpublished content items, check the boxes in the left column (right column in right-to-left languages) to select the desired content items. For <em>Action</em>, select the <em>Publish content</em> action. Click <em>Apply to selected items</em> to make the change. The other actions under <em>Action</em> work in a similar manner.{% endtrans %}</li>
+</ol>
+<h2>{% trans %}Additional resources{% endtrans %}</h2>
+<ul>
+  <li><a href="https://www.drupal.org/docs/user_guide/en/content-chapter.html">{% trans %}User Guide: Basic page management{% endtrans %}</a></li>
+  <li><a href="https://www.drupal.org/docs/user_guide/en/content-edit.html">{% trans %}User Guide: Editing a content item{% endtrans %}</a></li>
+</ul>
diff --git a/web/core/modules/help_topics/help_topics/node.overview.html.twig b/web/core/modules/help_topics/help_topics/node.overview.html.twig
new file mode 100644
index 0000000000..1f28f60611
--- /dev/null
+++ b/web/core/modules/help_topics/help_topics/node.overview.html.twig
@@ -0,0 +1,19 @@
+---
+label: 'Managing content'
+top_level: true
+related:
+  - core.content_structure
+  - field_ui.add_field
+  - field_ui.manage_display
+  - field_ui.manage_form
+  - node.creating_type
+  - node.creating_content
+  - node.editing
+---
+{% set content_structure_topic = render_var(help_topic_link('core.content_structure')) %}
+<h2>{% trans %}What is a content item?{% endtrans %}</h2>
+<p>{% trans %}A <em>content item</em> is a type of content entity for page-level content, which can have fields that store text, HTML markup, images, attached files, and other data. See {{ content_structure_topic }} for more about content entities and fields.{% endtrans %}</p>
+<h2>{% trans %}What is a content type?{% endtrans %}</h2>
+<p>{% trans %}Content items are divided into <em>content types</em>, which are the entity sub-types for the content item entity type; each content type has its own fields and display settings. For example, you might set up content types for pages, articles, recipes, events, and blog entries on your web site.{% endtrans %}</p>
+<h2>{% trans %}Overview of managing content{% endtrans %}</h2>
+<p>{% trans %}The core Node module allows you to define content types, and add and edit content items. The core Field UI module allows you to attach fields to each content type and manage the edit form and display for each content type. See the related topics listed below for specific tasks. Many other core and contributed modules and installation profiles provide pre-defined content types, modify the permission structure for content items, and provide other functionality.{% endtrans %}</p>
diff --git a/web/core/modules/help_topics/help_topics/path.creating_alias.html.twig b/web/core/modules/help_topics/help_topics/path.creating_alias.html.twig
new file mode 100644
index 0000000000..28162d2e49
--- /dev/null
+++ b/web/core/modules/help_topics/help_topics/path.creating_alias.html.twig
@@ -0,0 +1,28 @@
+---
+label: 'Creating a URL alias for a content item'
+related:
+  - path.overview
+  - path.editing_alias
+  - node.creating_content
+  - node.editing
+---
+{% set path_permissions_link_text %}
+{% trans %}Create and edit URL aliases{% endtrans %}
+{% endset %}
+{% set path_permissions_link = render_var(help_route_link(path_permissions_link_text, 'user.admin_permissions', {}, {'fragment': 'module-path'})) %}
+{% set overview_topic = render_var(help_topic_link('path.overview')) %}
+<h2>{% trans %}Goal{% endtrans %}</h2>
+<p>{% trans %}Give a content item page a human- or SEO-friendly URL alias; you can follow similar steps to create an alias for a taxonomy term page. See {{ overview_topic }} for more about aliases.{% endtrans %}</p>
+<h2>{% trans %}Who can create URL aliases?{% endtrans %}</h2>
+<p>{% trans %}Users with the <em>{{ path_permissions_link }}</em> permission can create aliases. To follow the steps in this topic, you will also need permission to edit the content item.{% endtrans %}</p>
+<h2>{% trans %}Steps{% endtrans %}</h2>
+<ol>
+  <li>{% trans %}Locate and open the content edit form for the content item, or create a new content item (see related topics on creating and editing content).{% endtrans %}</li>
+  <li>{% trans %}Under <em>URL alias</em> on the edit form, enter the desired alias (for example, "/about-us"). Make sure the alias starts with a "/" character.{% endtrans %}</li>
+  <li>{% trans %}Click <em>Save</em>.{% endtrans %}</li>
+  <li>{% trans %}Verify that the page can be visited with the new alias, for example <em>https://example.com/about-us</em>.{% endtrans %}</li>
+</ol>
+<h2>{% trans %}Additional resources{% endtrans %}</h2>
+<ul>
+  <li><a href="https://www.drupal.org/docs/user_guide/en/content-create.html">{% trans %}User guide: Creating a Content Item{% endtrans %}</a></li>
+</ul>
diff --git a/web/core/modules/help_topics/help_topics/path.editing_alias.html.twig b/web/core/modules/help_topics/help_topics/path.editing_alias.html.twig
new file mode 100644
index 0000000000..518525bed8
--- /dev/null
+++ b/web/core/modules/help_topics/help_topics/path.editing_alias.html.twig
@@ -0,0 +1,26 @@
+---
+label: 'Editing a URL alias'
+related:
+  - path.overview
+  - path.creating_alias
+---
+{% set path_permissions_link_text %}
+  {% trans %}Administer URL aliases{% endtrans %}
+{% endset %}
+{% set path_permissions_link = render_var(help_route_link(path_permissions_link_text, 'user.admin_permissions', {}, {'fragment': 'module-path'})) %}
+{% set path_aliases_link_text %}
+  {% trans %}URL aliases{% endtrans %}
+{% endset %}
+{% set path_aliases_link = render_var(help_route_link(path_aliases_link_text, 'entity.path_alias.collection')) %}
+{% set path_overview_topic = render_var(help_topic_link('path.overview')) %}
+<h2>{% trans %}Goal{% endtrans %}</h2>
+<p>{% trans %}Change an existing URL alias, to correct the path or the alias value. See {{ path_overview_topic }} for more about aliases.{% endtrans %}</p>
+<h2>{% trans %}Who can manage URL aliases?{% endtrans %}</h2>
+<p>{% trans %}Users with the <em>{{ path_permissions_link }}</em> permission can edit aliases.{% endtrans %}</p>
+<h2>{% trans %}Steps{% endtrans %}</h2>
+<ol>
+  <li>{% trans %}In the <em>Manage</em> administration menu, navigate to <em>Configuration</em> &gt; <em>Search and metadata</em> &gt; <em>{{ path_aliases_link }}</em>. A list of all the site's aliases will appear.{% endtrans %}</li>
+  <li>{% trans %}Click <em>Edit</em> in the dropdown button for the alias that you would like to change.{% endtrans %}</li>
+  <li>{% trans %}Make the required changes and click <em>Save</em>. You will be returned to the URL alias list page.{% endtrans %}</li>
+  <li>{% trans %}Note that you can also add new aliases from this page, for any path on your site.{% endtrans %}</li>
+</ol>
diff --git a/web/core/modules/help_topics/help_topics/path.overview.html.twig b/web/core/modules/help_topics/help_topics/path.overview.html.twig
new file mode 100644
index 0000000000..d2982de004
--- /dev/null
+++ b/web/core/modules/help_topics/help_topics/path.overview.html.twig
@@ -0,0 +1,24 @@
+---
+label: 'Configuring aliases for URLs'
+top_level: true
+related:
+  - path.creating_alias
+  - path.editing_alias
+---
+<h2>{% trans %}What is a URL?{% endtrans %}</h2>
+<p>{% trans %}URL is the abbreviation for "Uniform Resource Locator", which is the page's address on the web. It is the "name" by which a browser identifies a page to display. In the example "Visit us at <em>example.com</em>.", <em>https://example.com</em> would be the URL for the home page of your website. Users use URLs to locate content on the web.{% endtrans %}</p>
+<h2>{% trans %}What is a path?{% endtrans %}</h2>
+<p>{% trans %}A path is the unique, last part of the URL for a specific function or piece of content. For example, for a page whose full URL is <em>https://example.com/node/7</em>, the path is <em>node/7</em>. Here are some examples of paths you might find in your site:{% endtrans %}</p>
+<ul>
+  <li>{% trans %}node/7: Path to a particular content item.{% endtrans %}</li>
+  <li>{% trans %}taxonomy/term/6: Path to a taxonomy term page.{% endtrans %}</li>
+  <li>{% trans %}user/3: Path to a user profile page.{% endtrans %}</li>
+</ul>
+<h2>{% trans %}What is an alias?{% endtrans %}</h2>
+<p>{% trans %}The core software allows you to provide more understandable URLs for pages on your site, which are called <em>aliases</em>. For example, if you have an "About Us" page with the path <em>node/7</em>, you can set up an alias of <em>about</em> so that your visitors will see it as <em>https://www.example.com/about</em>.{% endtrans %}</p>
+<h2>{% trans %}Overview of configuring paths, aliases, and URLs{% endtrans %}</h2>
+<p>{% trans %}The core Path module provides the URL aliasing functionality. The contributed <a href="https://www.drupal.org/project/pathauto">Pathauto</a> module allows you to configure automatically-generated URL aliases for content items and other pages. See the related topics listed below for specific tasks.{% endtrans %}</p>
+<h2>{% trans %}Additional resources{% endtrans %}</h2>
+<ul>
+  <li><a href="https://www.drupal.org/docs/user_guide/en/content-paths.html">{% trans %}User Guide topic on Paths{% endtrans %}</a></li>
+</ul>
diff --git a/web/core/modules/help_topics/help_topics/taxonomy.configuring.html.twig b/web/core/modules/help_topics/help_topics/taxonomy.configuring.html.twig
new file mode 100644
index 0000000000..aa032f3d79
--- /dev/null
+++ b/web/core/modules/help_topics/help_topics/taxonomy.configuring.html.twig
@@ -0,0 +1,36 @@
+---
+label: 'Configuring taxonomy'
+related:
+  - taxonomy.overview
+  - field_ui.reference_field
+  - field_ui.manage_display
+  - field_ui.manage_form
+---
+{% set taxonomy_permissions_link_text %}
+  {% trans %}Administer vocabularies and terms{% endtrans %}
+{% endset %}
+{% set taxonomy_permissions_link = render_var(help_route_link(taxonomy_permissions_link_text, 'user.admin_permissions', {}, {'fragment': 'module-taxonomy'})) %}
+{% set taxonomy_admin_link_text %}
+  {% trans %}Taxonomy{% endtrans %}
+{% endset %}
+{% set taxonomy_admin_link = render_var(help_route_link(taxonomy_admin_link_text, 'entity.taxonomy_vocabulary.collection')) %}
+{% set taxonomy_overview_topic = render_var(help_topic_link('taxonomy.overview')) %}
+{% set content_structure_topic = render_var(help_topic_link('core.content_structure')) %}
+<h2>{% trans %}Goal{% endtrans %}</h2>
+<p>{% trans %}Create a taxonomy vocabulary and add a reference field for that vocabulary to a content entity. See {{ taxonomy_overview_topic }} for information about taxonomy and {{ content_structure_topic }} for more on content entities.{% endtrans %}</p>
+<h2>{% trans %}Who can configure a taxonomy vocabulary?{% endtrans %}</h2>
+<p>{% trans %}Users with the <em>{{ taxonomy_permissions_link }}</em> permission can configure a vocabulary. To add a field in the administrative interface, the core Field UI module must be installed, and you will also need the <em>Administer fields</em> permission for the entity you are adding the field to.{% endtrans %}</p>
+<h2>{% trans %}Steps{% endtrans %}</h2>
+<ol>
+  <li>{% trans %}In the <em>Manage</em> administrative menu, navigate to <em>Structure</em> &gt; <em>{{ taxonomy_admin_link }}</em>.{% endtrans %}</li>
+  <li>{% trans %}Click <em>Add vocabulary</em>.{% endtrans %}</li>
+  <li>{% trans %}In the <em>Name</em> field, enter a name for the vocabulary (for example "Ingredients"), which is how it will be shown in the administrative interface. Optionally, add a description.{% endtrans %}</li>
+  <li>{% trans %}Click <em>Save</em>. Your vocabulary will be created and you will see the page that lists all the terms in this vocabulary.{% endtrans %}</li>
+  <li>{% trans %}Optionally, click <em>Add term</em> to add a term to the new vocabulary. In the <em>Name</em> field, enter the term name (for example "Butter"). Click <em>Save</em>. You will receive a confirmation about the term you created. You may optionally continue to add more terms.{% endtrans %}</li>
+  <li>{% trans %}If you have the Field UI module installed, follow the instructions on the related <em>Adding a reference field to an entity sub-type</em> topic to add a taxonomy reference field to the entity type of your choice. The settings page will allow you to choose the <em>Vocabulary</em> that you created as the vocabulary to reference.{% endtrans %}</li>
+  <li>{% trans %}You may also want to configure the display and form display of the new field (see related topics).{% endtrans %}</li>
+</ol>
+<h2>{% trans %}Additional resources{% endtrans %}</h2>
+<ul>
+  <li><a href="https://www.drupal.org/docs/user_guide/en/structure-taxonomy-setup.html">{% trans %}User Guide: Setting up a taxonomy{% endtrans %}</a></li>
+</ul>
diff --git a/web/core/modules/help_topics/help_topics/taxonomy.overview.html.twig b/web/core/modules/help_topics/help_topics/taxonomy.overview.html.twig
new file mode 100644
index 0000000000..0e4d77bb85
--- /dev/null
+++ b/web/core/modules/help_topics/help_topics/taxonomy.overview.html.twig
@@ -0,0 +1,24 @@
+---
+label: 'Managing taxonomy'
+top_level: true
+---
+{% set content_structure_topic = render_var(help_topic_link('core.content_structure')) %}
+<h2>{% trans %}What is taxonomy?{% endtrans %}</h2>
+<p>{% trans %}<em>Taxonomy</em> is used to classify website content. One common example of taxonomy is the tags used to classify or categorize posts in a blog website; a cooking website could use an ingredients taxonomy to classify recipes. Individual taxonomy items are known as <em>terms</em> (the blog tags or recipe ingredients in these examples); and a set of terms is known as a <em>vocabulary</em> (the set of all blog post tags, or the set of all recipe ingredients in these examples). Technically, taxonomy terms are an entity type and the entity subtypes are the vocabularies; see {{ content_structure_topic }} for more on content entities. Like other entities, taxonomy terms can have fields attached; for instance, you could set up an image field to contain an icon for each term.{% endtrans %}</p>
+<p>{% trans %}An individual vocabulary can organize its terms in a hierarchy, or it could be flat. For example, blog tags normally have a flat structure, while a recipe ingredients vocabulary could be hierarchical (for example, tomatoes could be a sub-term of vegetables, and under tomatoes, you could have green and red tomatoes).{% endtrans %}</p>
+<p>{% trans %}Taxonomy terms are normally attached as reference fields to other content entities, which is how you can use them to classify content. When you set up a taxonomy reference field, you can let users enter terms in two ways:{% endtrans %}</p>
+<dl>
+  <dt>{% trans %}Free tagging{% endtrans %}</dt>
+  <dd>{% trans %}New terms can be created right on the content editing form.{% endtrans %}</dd>
+  <dt>{% trans %}Fixed list of terms{% endtrans %}</dt>
+  <dd>{% trans %}The list of terms is curated and managed outside the content editing form, and users can only select from the existing list when editing content.{% endtrans %}</dd>
+</dl>
+<p>{% trans %}Taxonomy reference fields can be added to any entity, such as user accounts, custom blocks, or regular content items. If you use them to classify regular content items, your site will automatically be set up with taxonomy listing pages for each term; each of these pages lists all of the content items that are classified with that term.{% endtrans %}</p>
+<h2>{% trans %}Overview of managing taxonomy{% endtrans %}</h2>
+<p>{% trans %}The core Taxonomy module allows you to create and edit taxonomy vocabularies and taxonomy terms. The core Field UI module provides a user interface for adding fields to entities, including the taxonomy reference field, and configuring field editing and display. See the related topics listed below for specific tasks.{% endtrans %}</p>
+<h2>{% trans %}Additional resources{% endtrans %}</h2>
+<ul>
+  <li><a
+      href="https://www.drupal.org/docs/user_guide/en/structure-taxonomy.html">{% trans %}User guide on Taxonomy{% endtrans %}</a>
+  </li>
+</ul>
diff --git a/web/core/modules/help_topics/help_topics/views.overview.html.twig b/web/core/modules/help_topics/help_topics/views.overview.html.twig
index a039f6ce7c..0e93040e45 100644
--- a/web/core/modules/help_topics/help_topics/views.overview.html.twig
+++ b/web/core/modules/help_topics/help_topics/views.overview.html.twig
@@ -3,6 +3,9 @@ label: 'Managing content listings (views)'
 top_level: true
 related:
   - block.overview
+  - views_ui.bulk_operations
+  - action.overview
+  - user.overview
 ---
 <h2>{% trans %}What is a view?{% endtrans %}</h2>
 <p>{% trans %}A <em>view</em> is a listing of items on your site; for example, a block showing the most recent comments, a page listing news items, or a list of registered users. The listings can be formatted in a table, grid, list, calendar, RSS feed, and other formats (some output formats may require you to install additional contributed modules).{% endtrans %}</p>
@@ -14,7 +17,7 @@ related:
   <li>{% trans %}<em>Fields</em>: if the Format allows, the particular fields to display.{% endtrans %}</li>
   <li>{% trans %}<em>Filter criteria</em>: criteria to limit the data to output, such as whether the content is published, the type of content, etc. Filters can be <em>exposed</em> to let users choose how to filter the data.{% endtrans %}</li>
   <li>{% trans %}<em>Sort criteria</em>: how to order the data. Sorting can also be exposed to users.{% endtrans %}</li>
-  <li>{% trans %}<em>Page settings</em>, <em>Block settings</em>, etc.: settings specific to the display type, such as the URL for a page display.{% endtrans %}</li>
+  <li>{% trans %}<em>Page settings</em>, <em>Block settings</em>, etc.: settings specific to the display type, such as the URL for a page display. Most display types support an <em>Access</em> setting, where you can choose a Permission or Role that a user must have in order to see the view.{% endtrans %}</li>
   <li>{% trans %}<em>Header</em> and <em>Footer</em>: content to display at the top or bottom of the view display.{% endtrans %}</li>
   <li>{% trans %}<em>No results behavior</em>: what to do if the filter criteria result in having no data to display.{% endtrans %}</li>
   <li>{% trans %}<em>Pager</em>: how many items to display, and how to paginate if there are additional items to display.{% endtrans %}</li>
@@ -22,6 +25,8 @@ related:
   <li>{% trans %}<em>Advanced</em> &gt; <em>Relationships</em>: additional data to pull in and display, related in some way to the base data of the view (such as data about the user who created the content item).{% endtrans %}</li>
   <li>{% trans %}<em>Advanced</em> &gt; <em>Exposed form</em>: if you have exposed filters or sorts, how to display the form to the user.{% endtrans %}</li>
 </ul>
+<h2>{% trans %}What are bulk operations?{% endtrans %}</h2>
+<p>{% trans %}Views using a table display format can include a bulk operations form, which allows users with sufficient permission to select one or more items from the view and apply an administrative action to them. The bulk actions available are specific to the base data type of the view; for example, a view of content items could support bulk publishing and unpublishing actions. If you have the core Actions module installed, see the related topic "Configuring actions" for more about actions.{% endtrans %}</p>
 <h2>{% trans %}Managing views overview{% endtrans %}</h2>
 <p>{% trans %}The core Views module handles the display of views, and the core Views UI module allows you to create, edit, and delete views in the administrative interface. See the related topics listed below for specific tasks (if the Views UI module is installed).{% endtrans %}</p>
 <h2>{% trans %}Additional resources{% endtrans %}</h2>
diff --git a/web/core/modules/help_topics/help_topics/views_ui.bulk_operations.html.twig b/web/core/modules/help_topics/help_topics/views_ui.bulk_operations.html.twig
new file mode 100644
index 0000000000..2ccf9af4fe
--- /dev/null
+++ b/web/core/modules/help_topics/help_topics/views_ui.bulk_operations.html.twig
@@ -0,0 +1,30 @@
+---
+label: 'Adding a bulk operations form to a view'
+related:
+  - action.overview
+  - action.creating
+  - views.overview
+  - views_ui.create
+  - user.overview
+---
+{% set views_link_text %}
+  {% trans %}Views{% endtrans %}
+{% endset %}
+{% set views = render_var(help_route_link(views_link_text, 'entity.view.collection')) %}
+{% set views_permissions_link_text %}
+  {% trans %}Administer views{% endtrans %}
+{% endset %}
+{% set views_permissions = render_var(help_route_link(views_permissions_link_text, 'user.admin_permissions', {}, {'fragment': 'module-views_ui'})) %}
+<h2>{% trans %}Goal{% endtrans %}</h2>
+<p>{% trans %}Add one or more existing actions as bulk operations to an existing table-style view. If you have the core Actions module installed, see the related topic "Configuring actions" for more information about actions.{% endtrans %}</p>
+<h2>{% trans %}Who can edit views?{% endtrans %}</h2>
+<p>{% trans %}The core Views UI module will need to be installed and you will need <em>{{ views_permissions }}</em> permission in order to edit a view.{% endtrans %}</p>
+<h2>{% trans %}Steps{% endtrans %}</h2>
+<ol>
+  <li>{% trans %}In the <em>Manage</em> administrative menu, navigate to <em>Structure</em> &gt; <em>{{ views }}</em>. A list of all views is shown.{% endtrans %}</li>
+  <li>{% trans %}Find the view that you would like to edit, and click <em>Edit</em> from the the dropdown button. Note that bulk operations work best in a view with a Page display, and a Table format.{% endtrans %}</li>
+  <li>{% trans %}If there is not already an <em>Operations bulk form</em> in the <em>Fields</em> list for the view, click <em>Add</em> in the <em>Fields</em> section to add it. (The exact name of the bulk form field will vary, and may contain keywords like "bulk update", "form element" or "operations" -- not to be confused with <em>operations links</em>, which are applied to each item in a row.) If the bulk operations field already exists, click the field name to edit its settings.{% endtrans %}</li>
+  <li>{% trans %}Check the action(s) you want to make available in the <em>Selected actions</em> list and click <em>Apply (all displays)</em>.{% endtrans %}</li>
+  <li>{% trans %}Verify that the <em>Access</em> settings for the view are at least as restrictive as the permissions necessary to perform the bulk operations. People with permission to see the view, but who don't have permission to do the bulk operations, will experience problems.{% endtrans %}</li>
+  <li>{% trans %}Click <em>Save</em>. The action(s) will be available as bulk operations in the view.{% endtrans %}</li>
+</ol>
diff --git a/web/core/modules/help_topics/tests/src/Functional/HelpTopicSearchTest.php b/web/core/modules/help_topics/tests/src/Functional/HelpTopicSearchTest.php
index dfb747f854..84e34b3af4 100644
--- a/web/core/modules/help_topics/tests/src/Functional/HelpTopicSearchTest.php
+++ b/web/core/modules/help_topics/tests/src/Functional/HelpTopicSearchTest.php
@@ -263,6 +263,28 @@ public function testUninstall() {
     $this->assertSession()->statusCodeEquals(200);
   }
 
+  /**
+   * Tests uninstalling the search module.
+   */
+  public function testUninstallSearch() {
+    // Ensure we can uninstall search and use the help system without
+    // breaking.
+    $this->drupalLogin($this->rootUser);
+    $edit = [];
+    $edit['uninstall[search]'] = TRUE;
+    $this->drupalGet('admin/modules/uninstall');
+    $this->submitForm($edit, 'Uninstall');
+    $this->submitForm([], 'Uninstall');
+    $this->assertSession()->pageTextContains('The selected modules have been uninstalled.');
+    $this->drupalGet('admin/help');
+    $this->assertSession()->statusCodeEquals(200);
+
+    // Rebuild the container to reflect the latest changes.
+    $this->rebuildContainer();
+    $this->assertTrue(\Drupal::moduleHandler()->moduleExists('help_topics'), 'The help_topics module is still installed.');
+    $this->assertFalse(\Drupal::moduleHandler()->moduleExists('search'), 'The search module is uninstalled.');
+  }
+
   /**
    * Asserts that help search returned the expected number of results.
    *
diff --git a/web/core/modules/help_topics/tests/src/Unit/HelpTopicTwigTest.php b/web/core/modules/help_topics/tests/src/Unit/HelpTopicTwigTest.php
index 80cac2caf2..13e360ccf3 100644
--- a/web/core/modules/help_topics/tests/src/Unit/HelpTopicTwigTest.php
+++ b/web/core/modules/help_topics/tests/src/Unit/HelpTopicTwigTest.php
@@ -80,9 +80,9 @@ public function testDefinition() {
    * @covers ::getCacheMaxAge
    */
   public function testCacheInfo() {
-    $this->assertEquals($this->helpTopic->getCacheContexts(), []);
-    $this->assertEquals($this->helpTopic->getCacheTags(), ['core.extension']);
-    $this->assertEquals($this->helpTopic->getCacheMaxAge(), Cache::PERMANENT);
+    $this->assertEquals([], $this->helpTopic->getCacheContexts());
+    $this->assertEquals(['core.extension'], $this->helpTopic->getCacheTags());
+    $this->assertEquals(Cache::PERMANENT, $this->helpTopic->getCacheMaxAge());
   }
 
   /**
diff --git a/web/core/modules/image/src/Plugin/migrate/source/d6/ImageCachePreset.php b/web/core/modules/image/src/Plugin/migrate/source/d6/ImageCachePreset.php
index 662648d7ab..53596a0813 100644
--- a/web/core/modules/image/src/Plugin/migrate/source/d6/ImageCachePreset.php
+++ b/web/core/modules/image/src/Plugin/migrate/source/d6/ImageCachePreset.php
@@ -8,6 +8,11 @@
 /**
  * Drupal 6 imagecache presets source from database.
  *
+ * For available configuration keys, refer to the parent classes.
+ *
+ * @see \Drupal\migrate\Plugin\migrate\source\SqlBase
+ * @see \Drupal\migrate\Plugin\migrate\source\SourcePluginBase
+ *
  * @MigrateSource(
  *   id = "d6_imagecache_presets",
  *   source_module = "imagecache"
diff --git a/web/core/modules/image/src/Plugin/migrate/source/d7/ImageStyles.php b/web/core/modules/image/src/Plugin/migrate/source/d7/ImageStyles.php
index 070cc9bfdc..79d0082437 100644
--- a/web/core/modules/image/src/Plugin/migrate/source/d7/ImageStyles.php
+++ b/web/core/modules/image/src/Plugin/migrate/source/d7/ImageStyles.php
@@ -6,7 +6,12 @@
 use Drupal\migrate\Row;
 
 /**
- * Drupal image styles source from database.
+ * Drupal 7 image styles source from database.
+ *
+ * For available configuration keys, refer to the parent classes.
+ *
+ * @see \Drupal\migrate\Plugin\migrate\source\SqlBase
+ * @see \Drupal\migrate\Plugin\migrate\source\SourcePluginBase
  *
  * @MigrateSource(
  *   id = "d7_image_styles",
diff --git a/web/core/modules/image/tests/src/Functional/ImageFieldValidateTest.php b/web/core/modules/image/tests/src/Functional/ImageFieldValidateTest.php
index 0124dfd2be..cbb47a5605 100644
--- a/web/core/modules/image/tests/src/Functional/ImageFieldValidateTest.php
+++ b/web/core/modules/image/tests/src/Functional/ImageFieldValidateTest.php
@@ -182,14 +182,8 @@ public function testRequiredAttributes() {
     $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->assertSession()->elementExists('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->assertSession()->elementExists('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->assertSession()->pageTextContains('Alternative text field is required.');
     $this->assertSession()->pageTextContains('Title field is required.');
 
diff --git a/web/core/modules/image/tests/src/Kernel/ImageItemTest.php b/web/core/modules/image/tests/src/Kernel/ImageItemTest.php
index 339b202590..2884747213 100644
--- a/web/core/modules/image/tests/src/Kernel/ImageItemTest.php
+++ b/web/core/modules/image/tests/src/Kernel/ImageItemTest.php
@@ -155,7 +155,7 @@ public function testImageItemMalformed() {
     }
     catch (EntityStorageException $exception) {
       $this->assertInstanceOf(Warning::class, $exception->getPrevious());
-      $this->assertEquals($exception->getMessage(), 'Missing file with ID 9999.');
+      $this->assertEquals('Missing file with ID 9999.', $exception->getMessage());
       $this->assertEmpty($entity->image_test->width);
       $this->assertEmpty($entity->image_test->height);
     }
diff --git a/web/core/modules/image/tests/src/Kernel/Migrate/d7/MigrateImageStylesTest.php b/web/core/modules/image/tests/src/Kernel/Migrate/d7/MigrateImageStylesTest.php
index 0637a2092f..11d2a88e14 100644
--- a/web/core/modules/image/tests/src/Kernel/Migrate/d7/MigrateImageStylesTest.php
+++ b/web/core/modules/image/tests/src/Kernel/Migrate/d7/MigrateImageStylesTest.php
@@ -58,7 +58,7 @@ protected function assertEntity($id, $label, array $expected_effect_plugins, arr
 
     // Check the number of effects associated with the style.
     $effects = $style->getEffects();
-    $this->assertSame(count($expected_effect_plugins), count($effects));
+    $this->assertSameSize($expected_effect_plugins, $effects);
 
     $index = 0;
     foreach ($effects as $effect) {
diff --git a/web/core/modules/image/tests/src/Unit/ImageStyleTest.php b/web/core/modules/image/tests/src/Unit/ImageStyleTest.php
index e38d9152c1..a0fb5fd28d 100644
--- a/web/core/modules/image/tests/src/Unit/ImageStyleTest.php
+++ b/web/core/modules/image/tests/src/Unit/ImageStyleTest.php
@@ -113,7 +113,7 @@ public function testGetDerivativeExtension() {
     $extensions = ['jpeg', 'gif', 'png'];
     foreach ($extensions as $extension) {
       $extensionReturned = $image_style->getDerivativeExtension($extension);
-      $this->assertEquals($extensionReturned, 'png');
+      $this->assertEquals('png', $extensionReturned);
     }
   }
 
diff --git a/web/core/modules/inline_form_errors/tests/src/Unit/FormErrorHandlerTest.php b/web/core/modules/inline_form_errors/tests/src/Unit/FormErrorHandlerTest.php
index 29865fcde9..b4265043e1 100644
--- a/web/core/modules/inline_form_errors/tests/src/Unit/FormErrorHandlerTest.php
+++ b/web/core/modules/inline_form_errors/tests/src/Unit/FormErrorHandlerTest.php
@@ -118,18 +118,14 @@ protected function setUp(): void {
    * @covers ::setElementErrorsFromFormState
    */
   public function testErrorMessagesInline() {
-    $this->messenger->expects($this->at(0))
+    $this->messenger->expects($this->exactly(4))
       ->method('addError')
-      ->with('no title given');
-    $this->messenger->expects($this->at(1))
-      ->method('addError')
-      ->with('element is invisible');
-    $this->messenger->expects($this->at(2))
-      ->method('addError')
-      ->with('this missing element is invalid');
-    $this->messenger->expects($this->at(3))
-      ->method('addError')
-      ->with('3 errors have been found: <ul-comma-list-mock><li-mock>Test 1</li-mock><li-mock>Test 2 &amp; a half</li-mock><li-mock>Test 3</li-mock></ul-comma-list-mock>');
+      ->withConsecutive(
+        ['no title given', FALSE],
+        ['element is invisible', FALSE],
+        ['this missing element is invalid', FALSE],
+        ['3 errors have been found: <ul-comma-list-mock><li-mock>Test 1</li-mock><li-mock>Test 2 &amp; a half</li-mock><li-mock>Test 3</li-mock></ul-comma-list-mock>', FALSE],
+      );
 
     $this->renderer->expects($this->once())
       ->method('renderPlain')
@@ -164,31 +160,18 @@ public function testErrorMessagesInline() {
    * Tests that opting out of Inline Form Errors works.
    */
   public function testErrorMessagesNotInline() {
-    $this->messenger->expects($this->exactly(7))
-      ->method('addMessage');
-
     // Asserts all messages are summarized.
-    $this->messenger->expects($this->at(0))
-      ->method('addMessage')
-      ->with('invalid', 'error', FALSE);
-    $this->messenger->expects($this->at(1))
-      ->method('addMessage')
-      ->with('invalid', 'error', FALSE);
-    $this->messenger->expects($this->at(2))
-      ->method('addMessage')
-      ->with('invalid', 'error', FALSE);
-    $this->messenger->expects($this->at(3))
-      ->method('addMessage')
-      ->with('no error message', 'error', FALSE);
-    $this->messenger->expects($this->at(4))
-      ->method('addMessage')
-      ->with('no title given', 'error', FALSE);
-    $this->messenger->expects($this->at(5))
-      ->method('addMessage')
-      ->with('element is invisible', 'error', FALSE);
-    $this->messenger->expects($this->at(6))
+    $this->messenger->expects($this->exactly(7))
       ->method('addMessage')
-      ->with('this missing element is invalid', 'error', FALSE);
+      ->withConsecutive(
+        ['invalid', 'error', FALSE],
+        ['invalid', 'error', FALSE],
+        ['invalid', 'error', FALSE],
+        ['no error message', 'error', FALSE],
+        ['no title given', 'error', FALSE],
+        ['element is invisible', 'error', FALSE],
+        ['this missing element is invalid', 'error', FALSE],
+      );
 
     $this->renderer->expects($this->never())
       ->method('renderPlain');
diff --git a/web/core/modules/jsonapi/tests/src/Functional/NodeTest.php b/web/core/modules/jsonapi/tests/src/Functional/NodeTest.php
index 6800460182..b01134f627 100644
--- a/web/core/modules/jsonapi/tests/src/Functional/NodeTest.php
+++ b/web/core/modules/jsonapi/tests/src/Functional/NodeTest.php
@@ -407,7 +407,7 @@ protected function assertNormalizedFieldsAreCached($field_names) {
       ],
     ]);
     $cached_fields = $cache['#data']['fields'];
-    $this->assertCount(count($field_names), $cached_fields);
+    $this->assertSameSize($field_names, $cached_fields);
     array_walk($field_names, function ($field_name) use ($cached_fields) {
       $this->assertInstanceOf(
         CacheableNormalization::class,
diff --git a/web/core/modules/jsonapi/tests/src/Kernel/Normalizer/JsonApiDocumentTopLevelNormalizerTest.php b/web/core/modules/jsonapi/tests/src/Kernel/Normalizer/JsonApiDocumentTopLevelNormalizerTest.php
index 5e20e4b14a..f5be2140a2 100644
--- a/web/core/modules/jsonapi/tests/src/Kernel/Normalizer/JsonApiDocumentTopLevelNormalizerTest.php
+++ b/web/core/modules/jsonapi/tests/src/Kernel/Normalizer/JsonApiDocumentTopLevelNormalizerTest.php
@@ -253,8 +253,8 @@ public function testNormalize() {
     $normalized = $jsonapi_doc_object->getNormalization();
 
     // @see http://jsonapi.org/format/#document-jsonapi-object
-    $this->assertEquals($normalized['jsonapi']['version'], '1.0');
-    $this->assertEquals($normalized['jsonapi']['meta']['links']['self']['href'], 'http://jsonapi.org/format/1.0/');
+    $this->assertEquals('1.0', $normalized['jsonapi']['version']);
+    $this->assertEquals('http://jsonapi.org/format/1.0/', $normalized['jsonapi']['meta']['links']['self']['href']);
 
     $this->assertSame($normalized['data']['attributes']['title'], 'dummy_title');
     $this->assertEquals($normalized['data']['id'], $this->node->uuid());
@@ -338,7 +338,7 @@ public function testNormalizeRelated() {
     $normalized = $jsonapi_doc_object->getNormalization();
     $this->assertSame($normalized['data']['attributes']['name'], 'user1');
     $this->assertEquals($normalized['data']['id'], User::load(1)->uuid());
-    $this->assertEquals($normalized['data']['type'], 'user--user');
+    $this->assertEquals('user--user', $normalized['data']['type']);
     // Make sure that the cache tags for the includes and the requested entities
     // are bubbling as expected.
     $this->assertSame(['user:1'], $jsonapi_doc_object->getCacheTags());
diff --git a/web/core/modules/jsonapi/tests/src/Kernel/Query/FilterTest.php b/web/core/modules/jsonapi/tests/src/Kernel/Query/FilterTest.php
index 2cc221c0db..dda2195030 100644
--- a/web/core/modules/jsonapi/tests/src/Kernel/Query/FilterTest.php
+++ b/web/core/modules/jsonapi/tests/src/Kernel/Query/FilterTest.php
@@ -383,29 +383,29 @@ public function testCreateFromQueryParameterNested() {
     $root = $filter->root();
 
     // Make sure the implicit root group was added.
-    $this->assertEquals($root->conjunction(), 'AND');
+    $this->assertEquals('AND', $root->conjunction());
 
     // Ensure the or-group and the and-group were added correctly.
     $members = $root->members();
 
     // Ensure the OR group was added.
     $or_group = $members[0];
-    $this->assertEquals($or_group->conjunction(), 'OR');
+    $this->assertEquals('OR', $or_group->conjunction());
     $or_group_members = $or_group->members();
 
     // Make sure the nested OR group was added with the right conditions.
     $nested_or_group = $or_group_members[0];
-    $this->assertEquals($nested_or_group->conjunction(), 'OR');
+    $this->assertEquals('OR', $nested_or_group->conjunction());
     $nested_or_group_members = $nested_or_group->members();
-    $this->assertEquals($nested_or_group_members[0]->field(), 'field0');
-    $this->assertEquals($nested_or_group_members[1]->field(), 'field1');
+    $this->assertEquals('field0', $nested_or_group_members[0]->field());
+    $this->assertEquals('field1', $nested_or_group_members[1]->field());
 
     // Make sure the nested AND group was added with the right conditions.
     $nested_and_group = $or_group_members[1];
-    $this->assertEquals($nested_and_group->conjunction(), 'AND');
+    $this->assertEquals('AND', $nested_and_group->conjunction());
     $nested_and_group_members = $nested_and_group->members();
-    $this->assertEquals($nested_and_group_members[0]->field(), 'field2');
-    $this->assertEquals($nested_and_group_members[1]->field(), 'field3');
+    $this->assertEquals('field2', $nested_and_group_members[0]->field());
+    $this->assertEquals('field3', $nested_and_group_members[1]->field());
   }
 
   /**
diff --git a/web/core/modules/language/tests/src/Functional/LanguageConfigurationTest.php b/web/core/modules/language/tests/src/Functional/LanguageConfigurationTest.php
index 9f764f477d..2e0292da0a 100644
--- a/web/core/modules/language/tests/src/Functional/LanguageConfigurationTest.php
+++ b/web/core/modules/language/tests/src/Functional/LanguageConfigurationTest.php
@@ -113,7 +113,7 @@ public function testLanguageConfiguration() {
     $this->submitForm($edit, 'Save configuration');
     $this->assertSession()->pageTextContains('The prefix may only be left blank for the selected detection fallback language.');
 
-    //  Check that prefix cannot be changed to contain a slash.
+    // Check that prefix cannot be changed to contain a slash.
     $edit = [
       'prefix[en]' => 'foo/bar',
     ];
diff --git a/web/core/modules/language/tests/src/Unit/ConfigurableLanguageUnitTest.php b/web/core/modules/language/tests/src/Unit/ConfigurableLanguageUnitTest.php
index 58670f0255..ef02b319d9 100644
--- a/web/core/modules/language/tests/src/Unit/ConfigurableLanguageUnitTest.php
+++ b/web/core/modules/language/tests/src/Unit/ConfigurableLanguageUnitTest.php
@@ -37,8 +37,8 @@ public function testWeight() {
     // The weight, an integer. Used to order languages with larger positive
     // weights sinking items toward the bottom of lists.
     $configurableLanguage = new ConfigurableLanguage(['weight' => -5], 'configurable_language');
-    $this->assertEquals($configurableLanguage->getWeight(), -5);
-    $this->assertEquals($configurableLanguage->setWeight(13)->getWeight(), 13);
+    $this->assertEquals(-5, $configurableLanguage->getWeight());
+    $this->assertEquals(13, $configurableLanguage->setWeight(13)->getWeight());
   }
 
 }
diff --git a/web/core/modules/layout_builder/layout_builder.module b/web/core/modules/layout_builder/layout_builder.module
index 9878d34b76..4631de2547 100644
--- a/web/core/modules/layout_builder/layout_builder.module
+++ b/web/core/modules/layout_builder/layout_builder.module
@@ -233,6 +233,7 @@ function layout_builder_cron() {
  * Implements hook_plugin_filter_TYPE__CONSUMER_alter().
  */
 function layout_builder_plugin_filter_block__layout_builder_alter(array &$definitions, array $extra) {
+  unset($definitions['system_main_block']);
   // @todo Restore the page title block in https://www.drupal.org/node/2938129.
   unset($definitions['page_title_block']);
 }
diff --git a/web/core/modules/layout_builder/tests/src/Functional/LayoutBuilderTest.php b/web/core/modules/layout_builder/tests/src/Functional/LayoutBuilderTest.php
index 563c74b088..ba6f5bc41c 100644
--- a/web/core/modules/layout_builder/tests/src/Functional/LayoutBuilderTest.php
+++ b/web/core/modules/layout_builder/tests/src/Functional/LayoutBuilderTest.php
@@ -876,6 +876,7 @@ public function testLayoutBuilderChooseBlocksAlter() {
     // Verify that blocks explicitly removed are not present.
     $assert_session->linkNotExists('Help');
     $assert_session->linkNotExists('Sticky at top of lists');
+    $assert_session->linkNotExists('Main page content');
     $assert_session->linkNotExists('Page title');
 
     // Verify that Changed block is not present on first section.
diff --git a/web/core/modules/layout_builder/tests/src/FunctionalJavascript/BlockFilterTest.php b/web/core/modules/layout_builder/tests/src/FunctionalJavascript/BlockFilterTest.php
index aafeb01f15..d50e1fa400 100644
--- a/web/core/modules/layout_builder/tests/src/FunctionalJavascript/BlockFilterTest.php
+++ b/web/core/modules/layout_builder/tests/src/FunctionalJavascript/BlockFilterTest.php
@@ -65,7 +65,6 @@ public function testBlockFilter() {
 
     // Get all blocks, for assertions later.
     $blocks = $page->findAll('css', '.js-layout-builder-block-link');
-    $blocks_count = count($blocks);
     $categories = $page->findAll('css', '.js-layout-builder-category');
 
     $filter = $assert_session->elementExists('css', '.js-layout-builder-filter');
@@ -77,7 +76,7 @@ public function testBlockFilter() {
     $filter->setValue('a');
     $this->assertAnnounceContains($init_message);
     $visible_rows = $this->filterVisibleElements($blocks);
-    $this->assertCount($blocks_count, $visible_rows);
+    $this->assertSameSize($blocks, $visible_rows);
 
     // Get the Content Fields category, which will be closed before filtering.
     $contentFieldsCategory = $page->find('named', ['content', 'Content fields']);
diff --git a/web/core/modules/layout_builder/tests/src/FunctionalJavascript/BlockFormMessagesTest.php b/web/core/modules/layout_builder/tests/src/FunctionalJavascript/BlockFormMessagesTest.php
index bf1f96ca7e..4fccd1c842 100644
--- a/web/core/modules/layout_builder/tests/src/FunctionalJavascript/BlockFormMessagesTest.php
+++ b/web/core/modules/layout_builder/tests/src/FunctionalJavascript/BlockFormMessagesTest.php
@@ -44,7 +44,7 @@ protected function setUp(): void {
    */
   public function testValidationMessage() {
     // @todo Work out why this fixes random fails in this test.
-    //    https://www.drupal.org/project/drupal/issues/3055982
+    //   https://www.drupal.org/project/drupal/issues/3055982
     $this->getSession()->resizeWindow(800, 1000);
     $assert_session = $this->assertSession();
     $page = $this->getSession()->getPage();
diff --git a/web/core/modules/layout_builder/tests/src/FunctionalJavascript/ContentPreviewToggleTest.php b/web/core/modules/layout_builder/tests/src/FunctionalJavascript/ContentPreviewToggleTest.php
index ae72055cf6..01b76696c5 100644
--- a/web/core/modules/layout_builder/tests/src/FunctionalJavascript/ContentPreviewToggleTest.php
+++ b/web/core/modules/layout_builder/tests/src/FunctionalJavascript/ContentPreviewToggleTest.php
@@ -153,7 +153,7 @@ protected function assertOrderInPage(array $items) {
       return strpos($block_text, $items[$key]) !== FALSE;
     }, ARRAY_FILTER_USE_BOTH);
 
-    $this->assertCount(count($items), $blocks_with_expected_text);
+    $this->assertSameSize($items, $blocks_with_expected_text);
   }
 
 }
diff --git a/web/core/modules/layout_builder/tests/src/FunctionalJavascript/InlineBlockTest.php b/web/core/modules/layout_builder/tests/src/FunctionalJavascript/InlineBlockTest.php
index 7e5ee49503..bbcd3cf512 100644
--- a/web/core/modules/layout_builder/tests/src/FunctionalJavascript/InlineBlockTest.php
+++ b/web/core/modules/layout_builder/tests/src/FunctionalJavascript/InlineBlockTest.php
@@ -164,7 +164,7 @@ public function testNoLayoutSave($operation, $no_save_button_text, $confirm_butt
       $this->assertCount(1, $blocks);
       $block = array_pop($blocks);
       $this->assertEquals($block->getRevisionId(), $revision_id);
-      $this->assertEquals($block->get('body')->getValue()[0]['value'], 'The block body');
+      $this->assertEquals('The block body', $block->get('body')->getValue()[0]['value']);
     }
     else {
       // The block should not be visible.
diff --git a/web/core/modules/layout_builder/tests/src/FunctionalJavascript/MoveBlockFormTest.php b/web/core/modules/layout_builder/tests/src/FunctionalJavascript/MoveBlockFormTest.php
index c7a4af0c4d..3b857b10e5 100644
--- a/web/core/modules/layout_builder/tests/src/FunctionalJavascript/MoveBlockFormTest.php
+++ b/web/core/modules/layout_builder/tests/src/FunctionalJavascript/MoveBlockFormTest.php
@@ -147,7 +147,7 @@ protected function assertBlockTable(array $expected_block_labels) {
     $page = $this->getSession()->getPage();
     $this->assertSession()->assertWaitOnAjaxRequest();
     $block_tds = $page->findAll('css', '.layout-builder-components-table__block-label');
-    $this->assertCount(count($block_tds), $expected_block_labels);
+    $this->assertSameSize($block_tds, $expected_block_labels);
     /** @var \Behat\Mink\Element\NodeElement $block_td */
     foreach ($block_tds as $block_td) {
       $this->assertSame(array_shift($expected_block_labels), trim($block_td->getText()));
@@ -214,7 +214,7 @@ protected function assertRegionBlocksOrder($section_delta, $region, array $expec
 
     // Get all blocks currently in the region.
     $blocks = $page->findAll('css', "$region_selector [data-layout-block-uuid]");
-    $this->assertCount(count($expected_block_selectors), $blocks);
+    $this->assertSameSize($expected_block_selectors, $blocks);
 
     /** @var \Behat\Mink\Element\NodeElement $block */
     foreach ($blocks as $block) {
diff --git a/web/core/modules/layout_builder/tests/src/Kernel/LayoutBuilderEntityViewDisplayTest.php b/web/core/modules/layout_builder/tests/src/Kernel/LayoutBuilderEntityViewDisplayTest.php
index 5b3fece0b5..e806c0a581 100644
--- a/web/core/modules/layout_builder/tests/src/Kernel/LayoutBuilderEntityViewDisplayTest.php
+++ b/web/core/modules/layout_builder/tests/src/Kernel/LayoutBuilderEntityViewDisplayTest.php
@@ -83,11 +83,11 @@ public function testSetOverridable() {
 
     // Set Overridable to TRUE and ensure Layout Builder is enabled.
     $this->sectionStorage->setOverridable();
-    $this->assertEquals($this->sectionStorage->isLayoutBuilderEnabled(), TRUE);
+    $this->assertTrue($this->sectionStorage->isLayoutBuilderEnabled());
 
     // Ensure Layout Builder is still enabled after setting Overridable to FALSE.
     $this->sectionStorage->setOverridable(FALSE);
-    $this->assertEquals($this->sectionStorage->isLayoutBuilderEnabled(), TRUE);
+    $this->assertTrue($this->sectionStorage->isLayoutBuilderEnabled());
   }
 
 }
diff --git a/web/core/modules/link/src/Plugin/Field/FieldWidget/LinkWidget.php b/web/core/modules/link/src/Plugin/Field/FieldWidget/LinkWidget.php
index b4dbdd8c36..9bb9f8de5e 100644
--- a/web/core/modules/link/src/Plugin/Field/FieldWidget/LinkWidget.php
+++ b/web/core/modules/link/src/Plugin/Field/FieldWidget/LinkWidget.php
@@ -74,7 +74,7 @@ protected static function getUriAsDisplayableString($uri) {
       list($entity_type, $entity_id) = explode('/', substr($uri, 7), 2);
       // Show the 'entity:' URI as the entity autocomplete would.
       // @todo Support entity types other than 'node'. Will be fixed in
-      //    https://www.drupal.org/node/2423093.
+      //   https://www.drupal.org/node/2423093.
       if ($entity_type == 'node' && $entity = \Drupal::entityTypeManager()->getStorage($entity_type)->load($entity_id)) {
         $displayable_string = EntityAutocomplete::getEntityLabels([$entity]);
       }
@@ -111,11 +111,11 @@ protected static function getUserEnteredStringAsUri($string) {
     $entity_id = EntityAutocomplete::extractEntityIdFromAutocompleteInput($string);
     if ($entity_id !== NULL) {
       // @todo Support entity types other than 'node'. Will be fixed in
-      //    https://www.drupal.org/node/2423093.
+      //   https://www.drupal.org/node/2423093.
       $uri = 'entity:node/' . $entity_id;
     }
     // Support linking to nothing.
-    elseif (in_array($string, ['<nolink>', '<none>'], TRUE)) {
+    elseif (in_array($string, ['<nolink>', '<none>', '<button>'], TRUE)) {
       $uri = 'route:' . $string;
     }
     // Detect a schemeless string, map to 'internal:' URI.
@@ -202,7 +202,7 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen
     if ($this->supportsInternalLinks()) {
       $element['uri']['#type'] = 'entity_autocomplete';
       // @todo The user should be able to select an entity type. Will be fixed
-      //    in https://www.drupal.org/node/2423093.
+      //   in https://www.drupal.org/node/2423093.
       $element['uri']['#target_type'] = 'node';
       // Disable autocompletion when the first character is '/', '#' or '?'.
       $element['uri']['#attributes']['data-autocomplete-first-character-blacklist'] = '/#?';
@@ -216,12 +216,12 @@ public function formElement(FieldItemListInterface $items, $delta, array $elemen
     // element prefix and description.
     if (!$this->supportsExternalLinks()) {
       $element['uri']['#field_prefix'] = rtrim(Url::fromRoute('<front>', [], ['absolute' => TRUE])->toString(), '/');
-      $element['uri']['#description'] = $this->t('This must be an internal path such as %add-node. You can also start typing the title of a piece of content to select it. Enter %front to link to the front page. Enter %nolink to display link text only. Enter %button to display keyboard-accessible link text only.', ['%add-node' => '/node/add', '%front' => '<front>', '%nolink' => '<nolink>', '%button' => 'route:<button>']);
+      $element['uri']['#description'] = $this->t('This must be an internal path such as %add-node. You can also start typing the title of a piece of content to select it. Enter %front to link to the front page. Enter %nolink to display link text only. Enter %button to display keyboard-accessible link text only.', ['%add-node' => '/node/add', '%front' => '<front>', '%nolink' => '<nolink>', '%button' => '<button>']);
     }
     // If the field is configured to allow both internal and external links,
     // show a useful description.
     elseif ($this->supportsExternalLinks() && $this->supportsInternalLinks()) {
-      $element['uri']['#description'] = $this->t('Start typing the title of a piece of content to select it. You can also enter an internal path such as %add-node or an external URL such as %url. Enter %front to link to the front page. Enter %nolink to display link text only. Enter %button to display keyboard-accessible link text only.', ['%front' => '<front>', '%add-node' => '/node/add', '%url' => 'http://example.com', '%nolink' => '<nolink>', '%button' => 'route:<button>']);
+      $element['uri']['#description'] = $this->t('Start typing the title of a piece of content to select it. You can also enter an internal path such as %add-node or an external URL such as %url. Enter %front to link to the front page. Enter %nolink to display link text only. Enter %button to display keyboard-accessible link text only.', ['%front' => '<front>', '%add-node' => '/node/add', '%url' => 'http://example.com', '%nolink' => '<nolink>', '%button' => '<button>']);
     }
     // If the field is configured to allow only external links, show a useful
     // description.
diff --git a/web/core/modules/link/tests/src/Functional/LinkFieldTest.php b/web/core/modules/link/tests/src/Functional/LinkFieldTest.php
index 9827f753ab..2bc8656d22 100644
--- a/web/core/modules/link/tests/src/Functional/LinkFieldTest.php
+++ b/web/core/modules/link/tests/src/Functional/LinkFieldTest.php
@@ -821,6 +821,20 @@ public function testNoLinkUri() {
     $output = $this->renderTestEntity($id);
     $expected_link = (string) $this->container->get('link_generator')->generate('Title, none', Url::fromUri('route:<none>'));
     $this->assertStringContainsString($expected_link, $output);
+
+    // Test a link with a <button> uri.
+    $edit = [
+      "{$field_name}[0][title]" => 'Title, button',
+      "{$field_name}[0][uri]" => '<button>',
+    ];
+
+    $this->drupalGet('/entity_test/add');
+    $this->submitForm($edit, 'Save');
+    preg_match('|entity_test/manage/(\d+)|', $this->getUrl(), $match);
+    $id = $match[1];
+    $output = $this->renderTestEntity($id);
+    $expected_link = (string) $this->container->get('link_generator')->generate('Title, button', Url::fromUri('route:<button>'));
+    $this->assertStringContainsString($expected_link, $output);
   }
 
   /**
diff --git a/web/core/modules/locale/tests/src/Functional/LocaleImportFunctionalTest.php b/web/core/modules/locale/tests/src/Functional/LocaleImportFunctionalTest.php
index 4a19ffc7a4..902e080cea 100644
--- a/web/core/modules/locale/tests/src/Functional/LocaleImportFunctionalTest.php
+++ b/web/core/modules/locale/tests/src/Functional/LocaleImportFunctionalTest.php
@@ -209,7 +209,7 @@ public function testStandalonePoFile() {
       ->countQuery()
       ->execute()
       ->fetchField();
-    $this->assertEquals($count, 6, 'Customized translations successfully imported.');
+    $this->assertEquals(6, $count, 'Customized translations successfully imported.');
 
     // Try importing a .po file with overriding strings, and ensure existing
     // customized strings are kept.
diff --git a/web/core/modules/locale/tests/src/Functional/LocaleJavascriptTranslationTest.php b/web/core/modules/locale/tests/src/Functional/LocaleJavascriptTranslationTest.php
index 9855f7b1cb..6f1110fa77 100644
--- a/web/core/modules/locale/tests/src/Functional/LocaleJavascriptTranslationTest.php
+++ b/web/core/modules/locale/tests/src/Functional/LocaleJavascriptTranslationTest.php
@@ -107,7 +107,7 @@ public function testFileParsing() {
         $this->assertSame($context, $source_strings[$str]);
       }
 
-      $this->assertSame(count($test_strings), count($source_strings), 'Found correct number of source strings.');
+      $this->assertSameSize($test_strings, $source_strings, 'Found correct number of source strings.');
     }
   }
 
diff --git a/web/core/modules/media/src/Form/EditorMediaDialog.php b/web/core/modules/media/src/Form/EditorMediaDialog.php
index 1b52044dbd..ca8b7671a0 100644
--- a/web/core/modules/media/src/Form/EditorMediaDialog.php
+++ b/web/core/modules/media/src/Form/EditorMediaDialog.php
@@ -176,7 +176,7 @@ public function buildForm(array $form, FormStateInterface $form_state, EditorInt
       '#access' => $filter_caption->status && ($filter_html->status === FALSE || !empty($allowed_attributes['data-caption'])),
     ];
 
-    $view_mode_options = array_intersect_key($this->entityDisplayRepository->getViewModeOptions('media'), $media_embed_filter->settings['allowed_view_modes']);
+    $view_mode_options = array_intersect_key($this->entityDisplayRepository->getViewModeOptionsByBundle('media', $media->bundle()), $media_embed_filter->settings['allowed_view_modes']);
     $default_view_mode = static::getViewModeDefaultValue($view_mode_options, $media_embed_filter, $media_embed_element['data-view-mode'] ?? NULL);
 
     $form['view_mode'] = [
diff --git a/web/core/modules/media/tests/src/Functional/ProviderRepositoryTest.php b/web/core/modules/media/tests/src/Functional/ProviderRepositoryTest.php
index 8c583e4ba5..2e81efc6b7 100644
--- a/web/core/modules/media/tests/src/Functional/ProviderRepositoryTest.php
+++ b/web/core/modules/media/tests/src/Functional/ProviderRepositoryTest.php
@@ -3,6 +3,7 @@
 namespace Drupal\Tests\media\Functional;
 
 use Drupal\media\OEmbed\ProviderException;
+use GuzzleHttp\Psr7\Utils;
 
 /**
  * Tests the oEmbed provider repository.
@@ -28,7 +29,7 @@ class ProviderRepositoryTest extends MediaFunctionalTestBase {
    */
   public function testEmptyProviderList($content) {
     $response = $this->prophesize('\GuzzleHttp\Psr7\Response');
-    $response->getBody()->willReturn($content);
+    $response->getBody()->willReturn(Utils::streamFor($content));
 
     $client = $this->createMock('\GuzzleHttp\Client');
     $client->method('request')->withAnyParameters()->willReturn($response->reveal());
diff --git a/web/core/modules/media/tests/src/FunctionalJavascript/CKEditorIntegrationTest.php b/web/core/modules/media/tests/src/FunctionalJavascript/CKEditorIntegrationTest.php
index 547b0e456b..f60e345b8d 100644
--- a/web/core/modules/media/tests/src/FunctionalJavascript/CKEditorIntegrationTest.php
+++ b/web/core/modules/media/tests/src/FunctionalJavascript/CKEditorIntegrationTest.php
@@ -3,6 +3,7 @@
 namespace Drupal\Tests\media\FunctionalJavascript;
 
 use Drupal\Component\Utility\Html;
+use Drupal\Core\Entity\Entity\EntityViewDisplay;
 use Drupal\Core\Url;
 use Drupal\editor\Entity\Editor;
 use Drupal\field\Entity\FieldConfig;
@@ -1169,6 +1170,29 @@ public function testViewMode() {
       'enabled' => TRUE,
       'label' => 'View Mode 2',
     ])->save();
+    EntityViewMode::create([
+      'id' => 'media.view_mode_3',
+      'targetEntityType' => 'media',
+      'status' => TRUE,
+      'enabled' => TRUE,
+      'label' => 'View Mode 3',
+    ])->save();
+
+    // Only enable view mode 1 & 2 for Image.
+    EntityViewDisplay::create([
+      'id' => 'media.image.view_mode_1',
+      'targetEntityType' => 'media',
+      'status' => TRUE,
+      'bundle' => 'image',
+      'mode' => 'view_mode_1',
+    ])->save();
+    EntityViewDisplay::create([
+      'id' => 'media.image.view_mode_2',
+      'targetEntityType' => 'media',
+      'status' => TRUE,
+      'bundle' => 'image',
+      'mode' => 'view_mode_2',
+    ])->save();
 
     $filter_format = FilterFormat::load('test_format');
     $filter_format->setFilterConfig('media_embed', [
@@ -1179,6 +1203,7 @@ public function testViewMode() {
         'allowed_view_modes' => [
           'view_mode_1' => 'view_mode_1',
           'view_mode_2' => 'view_mode_2',
+          'view_mode_3' => 'view_mode_3',
         ],
       ],
     ])->save();
@@ -1188,6 +1213,7 @@ public function testViewMode() {
     $expected_config_dependencies = [
       'core.entity_view_mode.media.view_mode_1',
       'core.entity_view_mode.media.view_mode_2',
+      'core.entity_view_mode.media.view_mode_3',
     ];
     $dependencies = $filter_format->getDependencies();
     $this->assertArrayHasKey('config', $dependencies);
@@ -1207,6 +1233,7 @@ public function testViewMode() {
     $this->waitForMetadataDialog();
     $assert_session->optionExists('attributes[data-view-mode]', 'view_mode_1');
     $assert_session->optionExists('attributes[data-view-mode]', 'view_mode_2');
+    $assert_session->optionNotExists('attributes[data-view-mode]', 'view_mode_3');
     $assert_session->selectExists('attributes[data-view-mode]')->selectOption('view_mode_2');
     $this->submitDialog();
     $this->getSession()->switchToIFrame('ckeditor');
diff --git a/web/core/modules/media_library/media_library.module b/web/core/modules/media_library/media_library.module
index 5726a80a4a..1b6beb8707 100644
--- a/web/core/modules/media_library/media_library.module
+++ b/web/core/modules/media_library/media_library.module
@@ -375,7 +375,7 @@ function media_library_local_tasks_alter(&$local_tasks) {
  */
 function media_library_image_style_access(EntityInterface $entity, $operation, AccountInterface $account) {
   // Prevent the fallback 'media_library' image style from being deleted.
-  // @todo: Lock the image style instead of preventing delete access.
+  // @todo Lock the image style instead of preventing delete access.
   //   https://www.drupal.org/project/drupal/issues/2247293
   if ($operation === 'delete' && $entity->id() === 'media_library') {
     return AccessResult::forbidden();
@@ -459,7 +459,7 @@ function _media_library_configure_view_display(MediaTypeInterface $type) {
     $display->removeComponent($name);
   }
 
-  // @todo: Remove dependency on 'medium' and 'thumbnail' image styles from
+  // @todo Remove dependency on 'medium' and 'thumbnail' image styles from
   //   media and media library modules.
   //   https://www.drupal.org/project/drupal/issues/3030437
   $image_style = ImageStyle::load('medium');
diff --git a/web/core/modules/media_library/src/MediaLibraryUiBuilder.php b/web/core/modules/media_library/src/MediaLibraryUiBuilder.php
index 12f8e08a5c..b00bd7af94 100644
--- a/web/core/modules/media_library/src/MediaLibraryUiBuilder.php
+++ b/web/core/modules/media_library/src/MediaLibraryUiBuilder.php
@@ -225,7 +225,7 @@ protected function buildMediaTypeMenu(MediaLibraryState $state) {
       return [];
     }
 
-    // @todo: Add a class to the li element.
+    // @todo Add a class to the li element.
     //   https://www.drupal.org/project/drupal/issues/3029227
     $menu = [
       '#theme' => 'links__media_library_menu',
diff --git a/web/core/modules/menu_link_content/src/MenuLinkContentAccessControlHandler.php b/web/core/modules/menu_link_content/src/MenuLinkContentAccessControlHandler.php
index 0a7c8cc5a7..b08120194e 100644
--- a/web/core/modules/menu_link_content/src/MenuLinkContentAccessControlHandler.php
+++ b/web/core/modules/menu_link_content/src/MenuLinkContentAccessControlHandler.php
@@ -12,7 +12,7 @@
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
- * Defines the access control handler for the user entity type.
+ * Defines the access control handler for the menu link content entity type.
  */
 class MenuLinkContentAccessControlHandler extends EntityAccessControlHandler implements EntityHandlerInterface {
 
diff --git a/web/core/modules/menu_link_content/tests/src/Kernel/MenuLinksTest.php b/web/core/modules/menu_link_content/tests/src/Kernel/MenuLinksTest.php
index a5e2b16f24..afe0aee563 100644
--- a/web/core/modules/menu_link_content/tests/src/Kernel/MenuLinksTest.php
+++ b/web/core/modules/menu_link_content/tests/src/Kernel/MenuLinksTest.php
@@ -67,8 +67,8 @@ public function createLinkHierarchy($module = 'menu_test') {
     // Then create a simple link hierarchy:
     // - parent
     //   - child-1
-    //      - child-1-1
-    //      - child-1-2
+    //     - child-1-1
+    //     - child-1-2
     //   - child-2
     $base_options = [
       'title' => 'Menu link test',
diff --git a/web/core/modules/menu_link_content/tests/src/Kernel/Migrate/d7/MigrateMenuLinkTest.php b/web/core/modules/menu_link_content/tests/src/Kernel/Migrate/d7/MigrateMenuLinkTest.php
index a2df4a7ab5..dd3cac07df 100644
--- a/web/core/modules/menu_link_content/tests/src/Kernel/Migrate/d7/MigrateMenuLinkTest.php
+++ b/web/core/modules/menu_link_content/tests/src/Kernel/Migrate/d7/MigrateMenuLinkTest.php
@@ -81,7 +81,7 @@ public function testMenuLinks() {
     foreach ($tree as $menu_link_tree_element) {
       $children += $menu_link_tree_element->hasChildren;
       if ($menu_link_tree_element->link->getUrlObject()->toString() == 'http://bing.com') {
-        $this->assertEquals(reset($menu_link_tree_element->subtree)->link->getUrlObject()->toString(), 'http://google.com');
+        $this->assertEquals('http://google.com', reset($menu_link_tree_element->subtree)->link->getUrlObject()->toString());
         $google_found = TRUE;
       }
     }
diff --git a/web/core/modules/migrate/src/Plugin/migrate/process/MigrationLookup.php b/web/core/modules/migrate/src/Plugin/migrate/process/MigrationLookup.php
index 112ad73140..06b7c9a014 100644
--- a/web/core/modules/migrate/src/Plugin/migrate/process/MigrationLookup.php
+++ b/web/core/modules/migrate/src/Plugin/migrate/process/MigrationLookup.php
@@ -58,14 +58,32 @@
  * process:
  *   uid:
  *     plugin: migration_lookup
- *       migration:
- *         - users
- *         - members
- *       source_ids:
- *         users:
- *           - author
- *         members:
- *           - id
+ *     migration:
+ *       - users
+ *       - members
+ *     source_ids:
+ *       users:
+ *         - author
+ *       members:
+ *         - id
+ * @endcode
+ *
+ * It's not required to describe source identifiers for each migration. If the
+ * source identifier for a migration is not specified, the default source value
+ * will be used. In the example below, the 'author' source property will be used
+ * to do a lookup in the 'users' migration, and the 'uid' property in the
+ * 'members' migration.
+ * @code
+ * process:
+ *   uid:
+ *     plugin: migration_lookup
+ *     source: uid
+ *     migration:
+ *       - users
+ *       - members
+ *     source_ids:
+ *       users:
+ *         - author
  * @endcode
  *
  * If the migration_lookup plugin does not find the source ID in the migration
@@ -178,22 +196,21 @@ public function transform($value, MigrateExecutableInterface $migrate_executable
     $destination_ids = NULL;
     $source_id_values = [];
     foreach ($lookup_migration_ids as $lookup_migration_id) {
+      $lookup_value = $value;
       if ($lookup_migration_id == $this->migration->id()) {
         $self = TRUE;
       }
       if (isset($this->configuration['source_ids'][$lookup_migration_id])) {
-        $value = array_values($row->getMultiple($this->configuration['source_ids'][$lookup_migration_id]));
-      }
-      if (!is_array($value)) {
-        $value = [$value];
+        $lookup_value = array_values($row->getMultiple($this->configuration['source_ids'][$lookup_migration_id]));
       }
-      $this->skipInvalid($value);
-      $source_id_values[$lookup_migration_id] = $value;
+      $lookup_value = (array) $lookup_value;
+      $this->skipInvalid($lookup_value);
+      $source_id_values[$lookup_migration_id] = $lookup_value;
 
       // Re-throw any PluginException as a MigrateException so the executable
       // can shut down the migration.
       try {
-        $destination_id_array = $this->migrateLookup->lookup($lookup_migration_id, $value);
+        $destination_id_array = $this->migrateLookup->lookup($lookup_migration_id, $lookup_value);
       }
       catch (PluginNotFoundException $e) {
         $destination_id_array = [];
diff --git a/web/core/modules/migrate/src/Plugin/migrate/source/SqlBase.php b/web/core/modules/migrate/src/Plugin/migrate/source/SqlBase.php
index 954f8f16b7..0788817015 100644
--- a/web/core/modules/migrate/src/Plugin/migrate/source/SqlBase.php
+++ b/web/core/modules/migrate/src/Plugin/migrate/source/SqlBase.php
@@ -276,7 +276,7 @@ protected function initializeIterator() {
       //    conditions, so we need to OR them together (but AND with any existing
       //    conditions in the query). So, ultimately the SQL condition will look
       //    like (original conditions) AND (map IS NULL OR map needs update
-      //      OR above high water).
+      //    OR above high water).
       $conditions = $this->query->orConditionGroup();
       $condition_added = FALSE;
       $added_fields = [];
diff --git a/web/core/modules/migrate/tests/src/Functional/process/DownloadFunctionalTest.php b/web/core/modules/migrate/tests/src/Functional/process/DownloadFunctionalTest.php
index 9ca3d992c1..9464450f7f 100644
--- a/web/core/modules/migrate/tests/src/Functional/process/DownloadFunctionalTest.php
+++ b/web/core/modules/migrate/tests/src/Functional/process/DownloadFunctionalTest.php
@@ -59,7 +59,7 @@ public function testExceptionThrow() {
     $result = $executable->import();
 
     // Check that the migration has completed.
-    $this->assertEquals($result, MigrationInterface::RESULT_COMPLETED);
+    $this->assertEquals(MigrationInterface::RESULT_COMPLETED, $result);
 
     /** @var \Drupal\migrate\Plugin\MigrateIdMapInterface $id_map_plugin */
     $id_map_plugin = $migration->getIdMap();
diff --git a/web/core/modules/migrate/tests/src/Kernel/MigrateBundleTest.php b/web/core/modules/migrate/tests/src/Kernel/MigrateBundleTest.php
index 2babdc1ab2..4f49b6fc1f 100644
--- a/web/core/modules/migrate/tests/src/Kernel/MigrateBundleTest.php
+++ b/web/core/modules/migrate/tests/src/Kernel/MigrateBundleTest.php
@@ -68,7 +68,7 @@ public function testDestinationBundle() {
     $term_executable->import();
     /** @var \Drupal\taxonomy\Entity\Term $term */
     $term = Term::load(1);
-    $this->assertEquals($term->bundle(), 'categories');
+    $this->assertEquals('categories', $term->bundle());
   }
 
   /**
@@ -106,9 +106,9 @@ public function testProcessBundle() {
     $term_executable->import();
     /** @var \Drupal\taxonomy\Entity\Term $term */
     $term = Term::load(1);
-    $this->assertEquals($term->bundle(), 'categories');
+    $this->assertEquals('categories', $term->bundle());
     $term = Term::load(2);
-    $this->assertEquals($term->bundle(), 'tags');
+    $this->assertEquals('tags', $term->bundle());
   }
 
   /**
@@ -148,9 +148,9 @@ public function testMixedBundles() {
     $term_executable->import();
     /** @var \Drupal\taxonomy\Entity\Term $term */
     $term = Term::load(1);
-    $this->assertEquals($term->bundle(), 'categories');
+    $this->assertEquals('categories', $term->bundle());
     $term = Term::load(2);
-    $this->assertEquals($term->bundle(), 'tags');
+    $this->assertEquals('tags', $term->bundle());
   }
 
 }
diff --git a/web/core/modules/migrate/tests/src/Kernel/MigrateSkipRowTest.php b/web/core/modules/migrate/tests/src/Kernel/MigrateSkipRowTest.php
index 6ccafe0eba..b131f48eea 100644
--- a/web/core/modules/migrate/tests/src/Kernel/MigrateSkipRowTest.php
+++ b/web/core/modules/migrate/tests/src/Kernel/MigrateSkipRowTest.php
@@ -86,7 +86,7 @@ public function testPrepareRowSkip() {
 
     $executable = new MigrateExecutable($migration);
     $result = $executable->import();
-    $this->assertEquals($result, MigrationInterface::RESULT_COMPLETED);
+    $this->assertEquals(MigrationInterface::RESULT_COMPLETED, $result);
 
     $id_map_plugin = $migration->getIdMap();
 
diff --git a/web/core/modules/migrate/tests/src/Unit/MigrateExecutableMemoryExceededTest.php b/web/core/modules/migrate/tests/src/Unit/MigrateExecutableMemoryExceededTest.php
index cea9e65328..acf3e64c09 100644
--- a/web/core/modules/migrate/tests/src/Unit/MigrateExecutableMemoryExceededTest.php
+++ b/web/core/modules/migrate/tests/src/Unit/MigrateExecutableMemoryExceededTest.php
@@ -78,16 +78,20 @@ protected function runMemoryExceededTest($message, $memory_exceeded, $memory_usa
     $this->executable->setMemoryUsage($memory_usage_first ?: $this->memoryLimit, $memory_usage_second ?: $this->memoryLimit);
     $this->executable->setMemoryThreshold(0.85);
     if ($message) {
-      $this->executable->message->expects($this->at(0))
+      $this->executable->message->expects($this->exactly(2))
         ->method('display')
-        ->with($this->callback(function ($subject) {
-            return mb_stripos((string) $subject, 'reclaiming memory') !== FALSE;
-        }));
-      $this->executable->message->expects($this->at(1))
-        ->method('display')
-        ->with($this->callback(function ($subject) use ($message) {
-            return mb_stripos((string) $subject, $message) !== FALSE;
-        }));
+        ->withConsecutive(
+          [
+            $this->callback(function ($subject) {
+              return mb_stripos((string) $subject, 'reclaiming memory') !== FALSE;
+            }),
+          ],
+          [
+            $this->callback(function ($subject) use ($message) {
+              return mb_stripos((string) $subject, $message) !== FALSE;
+            }),
+          ],
+        );
     }
     else {
       $this->executable->message->expects($this->never())
diff --git a/web/core/modules/migrate/tests/src/Unit/MigrateExecutableTest.php b/web/core/modules/migrate/tests/src/Unit/MigrateExecutableTest.php
index c542c7c46a..c0d7295c6e 100644
--- a/web/core/modules/migrate/tests/src/Unit/MigrateExecutableTest.php
+++ b/web/core/modules/migrate/tests/src/Unit/MigrateExecutableTest.php
@@ -408,7 +408,7 @@ public function testProcessRow() {
     foreach ($expected as $key => $value) {
       $this->assertSame($row->getDestinationProperty($key), $value);
     }
-    $this->assertSame(count($expected), count($row->getDestination()));
+    $this->assertSameSize($expected, $row->getDestination());
   }
 
   /**
diff --git a/web/core/modules/migrate/tests/src/Unit/MigrateSqlIdMapEnsureTablesTest.php b/web/core/modules/migrate/tests/src/Unit/MigrateSqlIdMapEnsureTablesTest.php
index e674ef4df7..826087933c 100644
--- a/web/core/modules/migrate/tests/src/Unit/MigrateSqlIdMapEnsureTablesTest.php
+++ b/web/core/modules/migrate/tests/src/Unit/MigrateSqlIdMapEnsureTablesTest.php
@@ -80,16 +80,7 @@ public function testEnsureTablesNotExist() {
         'source' => ['sourceid1', 'sourceid2'],
       ],
     ];
-    $schema = $this->getMockBuilder('Drupal\Core\Database\Schema')
-      ->disableOriginalConstructor()
-      ->getMock();
-    $schema->expects($this->at(0))
-      ->method('tableExists')
-      ->with('migrate_map_sql_idmap_test')
-      ->will($this->returnValue(FALSE));
-    $schema->expects($this->at(1))
-      ->method('createTable')
-      ->with('migrate_map_sql_idmap_test', $map_table_schema);
+
     // Now do the message table.
     $fields = [];
     $fields['msgid'] = [
@@ -120,15 +111,22 @@ public function testEnsureTablesNotExist() {
       'primary key' => ['msgid'],
     ];
 
-    $schema->expects($this->at(2))
+    $schema = $this->getMockBuilder('Drupal\Core\Database\Schema')
+      ->disableOriginalConstructor()
+      ->getMock();
+    $schema->expects($this->exactly(2))
       ->method('tableExists')
-      ->with('migrate_message_sql_idmap_test')
-      ->will($this->returnValue(FALSE));
-    $schema->expects($this->at(3))
+      ->willReturnMap([
+        ['migrate_map_sql_idmap_test', FALSE],
+        ['migrate_message_sql_idmap_test', FALSE],
+      ]);
+    $schema->expects($this->exactly(2))
       ->method('createTable')
-      ->with('migrate_message_sql_idmap_test', $table_schema);
-    $schema->expects($this->any())
-      ->method($this->anything());
+      ->withConsecutive(
+        ['migrate_map_sql_idmap_test', $map_table_schema],
+        ['migrate_message_sql_idmap_test', $table_schema],
+      );
+
     $this->runEnsureTablesTest($schema);
   }
 
@@ -139,53 +137,48 @@ public function testEnsureTablesExist() {
     $schema = $this->getMockBuilder('Drupal\Core\Database\Schema')
       ->disableOriginalConstructor()
       ->getMock();
-    $schema->expects($this->at(0))
+    $schema->expects($this->exactly(1))
       ->method('tableExists')
       ->with('migrate_map_sql_idmap_test')
-      ->will($this->returnValue(TRUE));
-    $schema->expects($this->at(1))
+      ->willReturn(TRUE);
+    $schema->expects($this->exactly(3))
       ->method('fieldExists')
-      ->with('migrate_map_sql_idmap_test', 'rollback_action')
-      ->will($this->returnValue(FALSE));
-    $field_schema = [
-      'type' => 'int',
-      'size' => 'tiny',
-      'unsigned' => TRUE,
-      'not null' => TRUE,
-      'default' => 0,
-      'description' => 'Flag indicating what to do for this item on rollback',
-    ];
-    $schema->expects($this->at(2))
-      ->method('addField')
-      ->with('migrate_map_sql_idmap_test', 'rollback_action', $field_schema);
-    $schema->expects($this->at(3))
-      ->method('fieldExists')
-      ->with('migrate_map_sql_idmap_test', 'hash')
-      ->will($this->returnValue(FALSE));
-    $field_schema = [
-      'type' => 'varchar',
-      'length' => '64',
-      'not null' => FALSE,
-      'description' => 'Hash of source row data, for detecting changes',
-    ];
-    $schema->expects($this->at(4))
+      ->willReturnMap([
+        ['migrate_map_sql_idmap_test', 'rollback_action', FALSE],
+        ['migrate_map_sql_idmap_test', 'hash', FALSE],
+        ['migrate_map_sql_idmap_test', 'source_ids_hash', FALSE],
+      ]);
+    $schema->expects($this->exactly(3))
       ->method('addField')
-      ->with('migrate_map_sql_idmap_test', 'hash', $field_schema);
-    $schema->expects($this->at(5))
-      ->method('fieldExists')
-      ->with('migrate_map_sql_idmap_test', 'source_ids_hash')
-      ->will($this->returnValue(FALSE));
-    $field_schema = [
-      'type' => 'varchar',
-      'length' => '64',
-      'not null' => TRUE,
-      'description' => 'Hash of source ids. Used as primary key',
-    ];
-    $schema->expects($this->at(6))
-      ->method('addField')
-      ->with('migrate_map_sql_idmap_test', 'source_ids_hash', $field_schema);
-    $schema->expects($this->exactly(7))
-      ->method($this->anything());
+      ->withConsecutive(
+        [
+          'migrate_map_sql_idmap_test', 'rollback_action', [
+            'type' => 'int',
+            'size' => 'tiny',
+            'unsigned' => TRUE,
+            'not null' => TRUE,
+            'default' => 0,
+            'description' => 'Flag indicating what to do for this item on rollback',
+          ],
+        ],
+        [
+          'migrate_map_sql_idmap_test', 'hash', [
+            'type' => 'varchar',
+            'length' => '64',
+            'not null' => FALSE,
+            'description' => 'Hash of source row data, for detecting changes',
+          ],
+        ],
+        [
+          'migrate_map_sql_idmap_test', 'source_ids_hash', [
+            'type' => 'varchar',
+            'length' => '64',
+            'not null' => TRUE,
+            'description' => 'Hash of source ids. Used as primary key',
+          ],
+        ],
+      );
+
     $this->runEnsureTablesTest($schema);
   }
 
diff --git a/web/core/modules/migrate/tests/src/Unit/MigrateSqlIdMapTest.php b/web/core/modules/migrate/tests/src/Unit/MigrateSqlIdMapTest.php
index 4d598d05d0..91c27b0400 100644
--- a/web/core/modules/migrate/tests/src/Unit/MigrateSqlIdMapTest.php
+++ b/web/core/modules/migrate/tests/src/Unit/MigrateSqlIdMapTest.php
@@ -328,7 +328,7 @@ public function testMessageSave() {
       $this->assertEquals($message_default, $message_row->message);
       $this->assertEquals(MigrationInterface::MESSAGE_ERROR, $message_row->level);
     }
-    $this->assertEquals($count, 1);
+    $this->assertEquals(1, $count);
 
     // Retrieve messages with a specific level.
     $messages = $id_map->getMessages([], MigrationInterface::MESSAGE_WARNING);
@@ -337,7 +337,7 @@ public function testMessageSave() {
       $count = 1;
       $this->assertEquals(MigrationInterface::MESSAGE_WARNING, $message_row->level);
     }
-    $this->assertEquals($count, 1);
+    $this->assertEquals(1, $count);
   }
 
   /**
diff --git a/web/core/modules/migrate/tests/src/Unit/MigrateTestCase.php b/web/core/modules/migrate/tests/src/Unit/MigrateTestCase.php
index 6425ff5392..ea79a0e9eb 100644
--- a/web/core/modules/migrate/tests/src/Unit/MigrateTestCase.php
+++ b/web/core/modules/migrate/tests/src/Unit/MigrateTestCase.php
@@ -157,7 +157,7 @@ protected function createSchemaFromRow(array $row) {
    *   An array of expected results.
    */
   public function queryResultTest($iter, $expected_results) {
-    $this->assertSame(count($expected_results), count($iter), 'Number of results match');
+    $this->assertSameSize($expected_results, $iter, 'Number of results match');
     $count = 0;
     foreach ($iter as $data_row) {
       $expected_row = $expected_results[$count];
diff --git a/web/core/modules/migrate/tests/src/Unit/destination/ConfigTest.php b/web/core/modules/migrate/tests/src/Unit/destination/ConfigTest.php
index d85d3d5fce..d55c21197b 100644
--- a/web/core/modules/migrate/tests/src/Unit/destination/ConfigTest.php
+++ b/web/core/modules/migrate/tests/src/Unit/destination/ConfigTest.php
@@ -56,7 +56,7 @@ public function testImport() {
       ->will($this->returnValue($config));
     $destination = new Config(['config_name' => 'd8_config'], 'd8_config', ['pluginId' => 'd8_config'], $migration, $config_factory, $language_manager);
     $destination_id = $destination->import($row);
-    $this->assertEquals($destination_id, ['d8_config']);
+    $this->assertEquals(['d8_config'], $destination_id);
   }
 
   /**
@@ -106,7 +106,7 @@ public function testLanguageImport() {
       ->will($this->returnValue($config));
     $destination = new Config(['config_name' => 'd8_config', 'translations' => 'true'], 'd8_config', ['pluginId' => 'd8_config'], $migration, $config_factory, $language_manager);
     $destination_id = $destination->import($row);
-    $this->assertEquals($destination_id, ['d8_config', 'mi']);
+    $this->assertEquals(['d8_config', 'mi'], $destination_id);
   }
 
 }
diff --git a/web/core/modules/migrate/tests/src/Unit/process/MigrationLookupTest.php b/web/core/modules/migrate/tests/src/Unit/process/MigrationLookupTest.php
index 4f931103ed..19919fd1a5 100644
--- a/web/core/modules/migrate/tests/src/Unit/process/MigrationLookupTest.php
+++ b/web/core/modules/migrate/tests/src/Unit/process/MigrationLookupTest.php
@@ -251,4 +251,37 @@ public function testMultipleSourceIds() {
     $this->assertEquals(2, $result);
   }
 
+  /**
+   * Tests processing multiple migrations and source IDs.
+   */
+  public function testMultipleMigrations() {
+    $migration_plugin = $this->prophesize(MigrationInterface::class);
+    $this->migrateLookup->lookup('foobaz', [1])->willReturn([[2]]);
+    $this->migrateLookup->lookup('foobaz', [2])->willReturn([]);
+    $this->migrateLookup->lookup('foobar', [1, 2])->willReturn([]);
+    $this->migrateLookup->lookup('foobar', [3, 4])->willReturn([[5]]);
+    $configuration = [
+      'migration' => ['foobar', 'foobaz'],
+      'source_ids' => [
+        'foobar' => ['foo', 'bar'],
+      ],
+    ];
+    $migration = MigrationLookup::create($this->prepareContainer(), $configuration, '', [], $migration_plugin->reveal());
+
+    $row1 = $this->row;
+    $row2 = clone $this->row;
+
+    $row1->expects($this->any())
+      ->method('getMultiple')
+      ->willReturn([1, 2]);
+    $result = $migration->transform([1], $this->migrateExecutable, $row1, '');
+    $this->assertEquals(2, $result);
+
+    $row2->expects($this->any())
+      ->method('getMultiple')
+      ->willReturn([3, 4]);
+    $result = $migration->transform([2], $this->migrateExecutable, $row2, '');
+    $this->assertEquals(5, $result);
+  }
+
 }
diff --git a/web/core/modules/migrate/tests/src/Unit/process/SubProcessTest.php b/web/core/modules/migrate/tests/src/Unit/process/SubProcessTest.php
index 22f181c79f..622a1e97dc 100644
--- a/web/core/modules/migrate/tests/src/Unit/process/SubProcessTest.php
+++ b/web/core/modules/migrate/tests/src/Unit/process/SubProcessTest.php
@@ -45,14 +45,14 @@ public function testSubProcess($process_configuration, $source_values = []) {
     foreach ($process_configuration['process'] as $destination => $source) {
       $sub_process_plugins[$destination][] = new Get(['source' => $source], 'get', []);
     }
-    $migration->expects($this->at(1))
-      ->method('getProcessPlugins')
-      ->willReturn($sub_process_plugins);
     // Set up the key plugins.
     $key_plugin['key'][] = new Get(['source' => '@id'], 'get', []);
-    $migration->expects($this->at(2))
+    $migration->expects($this->exactly(2))
       ->method('getProcessPlugins')
-      ->will($this->returnValue($key_plugin));
+      ->willReturnOnConsecutiveCalls(
+        $sub_process_plugins,
+        $key_plugin,
+      );
     $event_dispatcher = $this->createMock(EventDispatcherInterface::class);
     $migrate_executable = new MigrateExecutable($migration, $this->createMock(MigrateMessageInterface::class), $event_dispatcher);
 
@@ -71,7 +71,7 @@ public function testSubProcess($process_configuration, $source_values = []) {
     // key (@id) is the same as the destination ID (42).
     $new_value = $plugin->transform($current_value, $migrate_executable, $row, 'test');
     $this->assertCount(1, $new_value);
-    $this->assertCount(count($process_configuration['process']), $new_value[42]);
+    $this->assertSameSize($process_configuration['process'], $new_value[42]);
     $this->assertSame('test', $new_value[42]['foo']);
     if ($source_values) {
       $this->assertSame('source_baz', $new_value[42]['baaa']);
@@ -139,16 +139,13 @@ public function testNotFoundSubProcess($process_configuration, $source_values =
     foreach ($process_configuration['process'] as $destination => $source) {
       $sub_process_plugins[$destination][] = new Get(['source' => $source], 'get', []);
     }
-    $migration->expects($this->at(1))
+    $key_plugin['key'][] = new Get(['source' => '@id'], 'get', []);
+    $migration->expects($this->exactly(2))
       ->method('getProcessPlugins')
-      ->willReturn($sub_process_plugins);
-    // Set up the key plugins.
-    if (array_key_exists('key', $process_configuration)) {
-      $key_plugin['key'][] = new Get(['source' => '@id'], 'get', []);
-      $migration->expects($this->at(2))
-        ->method('getProcessPlugins')
-        ->will($this->returnValue($key_plugin));
-    }
+      ->willReturnOnConsecutiveCalls(
+        $sub_process_plugins,
+        $key_plugin,
+      );
     $event_dispatcher = $this->createMock(EventDispatcherInterface::class);
     $migrate_executable = new MigrateExecutable($migration, $this->createMock(MigrateMessageInterface::class), $event_dispatcher);
 
diff --git a/web/core/modules/migrate_drupal/migrations/state/migrate_drupal.migrate_drupal.yml b/web/core/modules/migrate_drupal/migrations/state/migrate_drupal.migrate_drupal.yml
index 5f0752cdd2..06dfde1996 100644
--- a/web/core/modules/migrate_drupal/migrations/state/migrate_drupal.migrate_drupal.yml
+++ b/web/core/modules/migrate_drupal/migrations/state/migrate_drupal.migrate_drupal.yml
@@ -4,10 +4,6 @@
 # cspell:ignore imageapi imagefield imagemagick multiupload
 finished:
   6:
-    nodereference: core
-    userreference: core
-    # Blog requires node.
-    blog: node
     # The following do not have an upgrade path.
     blogapi: core
     calendarsignup: core
@@ -47,8 +43,6 @@ finished:
     views_export: core
     views_ui: core
   7:
-    # Blog requires node.
-    blog: node
     # The following do not need have an upgrade path.
     bulk_export: core
     contextual: core
diff --git a/web/core/modules/migrate_drupal/src/Plugin/migrate/source/EmptySource.php b/web/core/modules/migrate_drupal/src/Plugin/migrate/source/EmptySource.php
index 8a95570917..7c6e2608eb 100644
--- a/web/core/modules/migrate_drupal/src/Plugin/migrate/source/EmptySource.php
+++ b/web/core/modules/migrate_drupal/src/Plugin/migrate/source/EmptySource.php
@@ -13,6 +13,12 @@
 /**
  * Source returning an empty row with Drupal specific config dependencies.
  *
+ * For more information and available configuration keys, refer to the parent
+ * classes.
+ *
+ * @see \Drupal\migrate\Plugin\migrate\source\EmptySource
+ * @see \Drupal\migrate\Plugin\migrate\source\SourcePluginBase
+ *
  * @MigrateSource(
  *   id = "md_empty",
  *   source_module = "system",
diff --git a/web/core/modules/migrate_drupal/src/Plugin/migrate/source/d7/FieldableEntity.php b/web/core/modules/migrate_drupal/src/Plugin/migrate/source/d7/FieldableEntity.php
index 1d2d16d3c7..dbb5ed67d6 100644
--- a/web/core/modules/migrate_drupal/src/Plugin/migrate/source/d7/FieldableEntity.php
+++ b/web/core/modules/migrate_drupal/src/Plugin/migrate/source/d7/FieldableEntity.php
@@ -59,7 +59,7 @@ protected function getFields($entity_type, $bundle = NULL) {
    *   (optional) The field language.
    *
    * @return array
-   *   The raw field values, keyed by delta.
+   *   The raw field values, keyed and sorted by delta.
    */
   protected function getFieldValues($entity_type, $field, $entity_id, $revision_id = NULL, $language = NULL) {
     $table = (isset($revision_id) ? 'field_revision_' : 'field_data_') . $field;
@@ -67,7 +67,8 @@ protected function getFieldValues($entity_type, $field, $entity_id, $revision_id
       ->fields('t')
       ->condition('entity_type', $entity_type)
       ->condition('entity_id', $entity_id)
-      ->condition('deleted', 0);
+      ->condition('deleted', 0)
+      ->orderBy('delta');
     if (isset($revision_id)) {
       $query->condition('revision_id', $revision_id);
     }
diff --git a/web/core/modules/migrate_drupal/tests/fixtures/drupal7.php b/web/core/modules/migrate_drupal/tests/fixtures/drupal7.php
index ec81792cd8..79374bd277 100644
--- a/web/core/modules/migrate_drupal/tests/fixtures/drupal7.php
+++ b/web/core/modules/migrate_drupal/tests/fixtures/drupal7.php
@@ -4617,6 +4617,21 @@
   'translatable' => '0',
   'deleted' => '0',
 ))
+->values(array(
+  'id' => '61',
+  'field_name' => 'field_checkbox',
+  'type' => 'list_boolean',
+  'module' => 'list',
+  'active' => '1',
+  'storage_type' => 'field_sql_storage',
+  'storage_module' => 'field_sql_storage',
+  'storage_active' => '1',
+  'locked' => '0',
+  'data' => 'a:7:{s:12:"translatable";i:0;s:12:"entity_types";a:0:{}s:8:"settings";a:3:{s:14:"allowed_values";a:2:{i:0;s:4:"Stop";i:1;s:2:"Go";}s:23:"allowed_values_function";s:0:"";s:23:"entity_translation_sync";b:0;}s:7:"storage";a:5:{s:4:"type";s:17:"field_sql_storage";s:8:"settings";a:0:{}s:6:"module";s:17:"field_sql_storage";s:6:"active";s:1:"1";s:7:"details";a:1:{s:3:"sql";a:2:{s:18:"FIELD_LOAD_CURRENT";a:1:{s:25:"field_data_field_checkbox";a:1:{s:5:"value";s:20:"field_checkbox_value";}}s:19:"FIELD_LOAD_REVISION";a:1:{s:29:"field_revision_field_checkbox";a:1:{s:5:"value";s:20:"field_checkbox_value";}}}}}s:12:"foreign keys";a:0:{}s:7:"indexes";a:1:{s:5:"value";a:1:{i:0;s:5:"value";}}s:2:"id";s:2:"53";}',
+  'cardinality' => '1',
+  'translatable' => '0',
+  'deleted' => '0',
+))
 ->execute();
 $connection->schema()->createTable('field_config_instance', array(
   'fields' => array(
@@ -5477,6 +5492,15 @@
   'data' => 'a:6:{s:5:"label";s:9:"image_miw";s:6:"widget";a:5:{s:6:"weight";s:2:"18";s:4:"type";s:9:"image_miw";s:6:"module";s:29:"multiupload_imagefield_widget";s:6:"active";i:1;s:8:"settings";a:2:{s:18:"progress_indicator";s:8:"throbber";s:19:"preview_image_style";s:9:"thumbnail";}}s:8:"settings";a:10:{s:14:"file_directory";s:0:"";s:15:"file_extensions";s:16:"png gif jpg jpeg";s:12:"max_filesize";s:0:"";s:14:"max_resolution";s:0:"";s:14:"min_resolution";s:0:"";s:9:"alt_field";i:0;s:11:"title_field";i:0;s:13:"default_image";i:0;s:18:"user_register_form";b:0;s:23:"entity_translation_sync";b:0;}s:7:"display";a:1:{s:7:"default";a:5:{s:5:"label";s:5:"above";s:4:"type";s:5:"image";s:8:"settings";a:2:{s:11:"image_style";s:0:"";s:10:"image_link";s:0:"";}s:6:"module";s:5:"image";s:6:"weight";i:16;}}s:8:"required";i:0;s:11:"description";s:0:"";}',
   'deleted' => '0',
 ))
+->values(array(
+  'id' => '93',
+  'field_id' => '61',
+  'field_name' => 'field_checkbox',
+  'entity_type' => 'node',
+  'bundle' => 'article',
+  'data' => 'a:7:{s:5:"label";s:8:"checkbox";s:6:"widget";a:5:{s:6:"weight";s:2:"25";s:4:"type";s:15:"options_buttons";s:6:"module";s:7:"options";s:6:"active";i:1;s:8:"settings";a:0:{}}s:8:"settings";a:2:{s:18:"user_register_form";b:0;s:23:"entity_translation_sync";b:0;}s:7:"display";a:1:{s:7:"default";a:5:{s:5:"label";s:5:"above";s:4:"type";s:12:"list_default";s:8:"settings";a:0:{}s:6:"module";s:4:"list";s:6:"weight";i:25;}}s:8:"required";i:0;s:11:"description";s:0:"";s:13:"default_value";N;}',
+  'deleted' => '0',
+))
 ->execute();
 $connection->schema()->createTable('field_data_body', array(
   'fields' => array(
@@ -5634,6 +5658,88 @@
   'body_format' => 'filtered_html',
 ))
 ->execute();
+$connection->schema()->createTable('field_data_field_checkbox', array(
+  'fields' => array(
+    'entity_type' => array(
+      'type' => 'varchar',
+      'not null' => TRUE,
+      'length' => '128',
+      'default' => '',
+    ),
+    'bundle' => array(
+      'type' => 'varchar',
+      'not null' => TRUE,
+      'length' => '128',
+      'default' => '',
+    ),
+    'deleted' => array(
+      'type' => 'int',
+      'not null' => TRUE,
+      'size' => 'tiny',
+      'default' => '0',
+    ),
+    'entity_id' => array(
+      'type' => 'int',
+      'not null' => TRUE,
+      'size' => 'normal',
+      'unsigned' => TRUE,
+    ),
+    'revision_id' => array(
+      'type' => 'int',
+      'not null' => FALSE,
+      'size' => 'normal',
+      'unsigned' => TRUE,
+    ),
+    'language' => array(
+      'type' => 'varchar',
+      'not null' => TRUE,
+      'length' => '32',
+      'default' => '',
+    ),
+    'delta' => array(
+      'type' => 'int',
+      'not null' => TRUE,
+      'size' => 'normal',
+      'unsigned' => TRUE,
+    ),
+    'field_checkbox_value' => array(
+      'type' => 'int',
+      'not null' => FALSE,
+      'size' => 'normal',
+    ),
+  ),
+  'primary key' => array(
+    'entity_type',
+    'entity_id',
+    'deleted',
+    'delta',
+    'language',
+  ),
+  'indexes' => array(
+    'entity_type' => array(
+      'entity_type',
+    ),
+    'bundle' => array(
+      'bundle',
+    ),
+    'deleted' => array(
+      'deleted',
+    ),
+    'entity_id' => array(
+      'entity_id',
+    ),
+    'revision_id' => array(
+      'revision_id',
+    ),
+    'language' => array(
+      'language',
+    ),
+    'field_checkbox_value' => array(
+      'field_checkbox_value',
+    ),
+  ),
+    'mysql_character_set' => 'utf8',
+  ));
 $connection->schema()->createTable('field_data_comment_body', array(
   'fields' => array(
     'entity_type' => array(
@@ -12047,6 +12153,90 @@
   'body_format' => 'filtered_html',
 ))
 ->execute();
+$connection->schema()->createTable('field_revision_field_checkbox', array(
+  'fields' => array(
+    'entity_type' => array(
+      'type' => 'varchar',
+      'not null' => TRUE,
+      'length' => '128',
+      'default' => '',
+    ),
+    'bundle' => array(
+      'type' => 'varchar',
+      'not null' => TRUE,
+      'length' => '128',
+      'default' => '',
+    ),
+    'deleted' => array(
+      'type' => 'int',
+      'not null' => TRUE,
+      'size' => 'tiny',
+      'default' => '0',
+    ),
+    'entity_id' => array(
+      'type' => 'int',
+      'not null' => TRUE,
+      'size' => 'normal',
+      'unsigned' => TRUE,
+    ),
+    'revision_id' => array(
+      'type' => 'int',
+      'not null' => TRUE,
+      'size' => 'normal',
+      'unsigned' => TRUE,
+    ),
+    'language' => array(
+      'type' => 'varchar',
+      'not null' => TRUE,
+      'length' => '32',
+      'default' => '',
+    ),
+    'delta' => array(
+      'type' => 'int',
+      'not null' => TRUE,
+      'size' => 'normal',
+      'unsigned' => TRUE,
+    ),
+    'field_checkbox_value' => array(
+      'type' => 'int',
+      'not null' => FALSE,
+      'size' => 'normal',
+    ),
+  ),
+  'primary key' => array(
+    'entity_type',
+    'entity_id',
+    'revision_id',
+    'deleted',
+    'delta',
+    'language',
+  ),
+  'indexes' => array(
+    'entity_type' => array(
+      'entity_type',
+    ),
+    'bundle' => array(
+      'bundle',
+    ),
+    'deleted' => array(
+      'deleted',
+    ),
+    'entity_id' => array(
+      'entity_id',
+    ),
+    'revision_id' => array(
+      'revision_id',
+    ),
+    'language' => array(
+      'language',
+    ),
+    'field_checkbox_value' => array(
+      'field_checkbox_value',
+    ),
+  ),
+  'mysql_character_set' => 'utf8',
+));
+
 $connection->schema()->createTable('field_revision_comment_body', array(
   'fields' => array(
     'entity_type' => array(
@@ -20920,6 +21110,26 @@
   'objectindex' => '467',
   'format' => '',
 ))
+->values(array(
+  'lid' => '805',
+  'textgroup' => 'field',
+  'context' => 'field_checkbox:#allowed_values:0',
+  'objectid' => '#allowed_values',
+  'type' => 'field_checkbox',
+  'property' => '0',
+  'objectindex' => '0',
+  'format' => '',
+))
+->values(array(
+  'lid' => '806',
+  'textgroup' => 'field',
+  'context' => 'field_checkbox:#allowed_values:1',
+  'objectid' => '#allowed_values',
+  'type' => 'field_checkbox',
+  'property' => '1',
+  'objectindex' => '0',
+  'format' => '',
+))
 ->execute();
 $connection->schema()->createTable('i18n_translation_set', array(
   'fields' => array(
@@ -22560,6 +22770,38 @@
   'plural' => '0',
   'i18n_status' => '0',
 ))
+->values(array(
+  'lid' => '805',
+  'translation' => 'is - Stop',
+  'language' => 'is',
+  'plid' => '0',
+  'plural' => '0',
+  'i18n_status' => '0',
+))
+->values(array(
+  'lid' => '806',
+  'translation' => 'is - Go',
+  'language' => 'is',
+  'plid' => '0',
+  'plural' => '0',
+  'i18n_status' => '0',
+))
+->values(array(
+  'lid' => '805',
+  'translation' => 'fr - Stop',
+  'language' => 'fr',
+  'plid' => '0',
+  'plural' => '0',
+  'i18n_status' => '0',
+))
+->values(array(
+  'lid' => '806',
+  'translation' => 'Go',
+  'language' => 'fr',
+  'plid' => '0',
+  'plural' => '0',
+  'i18n_status' => '0',
+))
 ->execute();
 $connection->schema()->createTable('menu_custom', array(
   'fields' => array(
@@ -56886,7 +57128,7 @@
   'info' => 'a:11:{s:4:"name";s:22:"Breakpoints Theme Test";s:11:"description";s:35:"Test breakpoints provided by themes";s:7:"package";s:5:"Other";s:4:"core";s:3:"7.x";s:6:"hidden";b:1;s:5:"mtime";i:1544938132;s:12:"dependencies";a:0:{}s:7:"version";N;s:3:"php";s:5:"5.2.4";s:5:"files";a:0:{}s:9:"bootstrap";i:0;}',
 ))
 ->values(array(
-  'filename' => 'sites/all/modules/contrib/multiupload_filefield_widget/multiupload_filefield_widget.module',
+  'filename' => 'sites/all/modules/multiupload_filefield_widget/multiupload_filefield_widget.module',
   'name' => 'multiupload_filefield_widget',
   'type' => 'module',
   'owner' => '',
@@ -56897,7 +57139,7 @@
   'info' => 'a:12:{s:4:"name";s:28:"Multiupload Filefield Widget";s:11:"description";s:76:"Creates a widget for filefield to upload multiple files at once using html5.";s:7:"package";s:6:"Fields";s:4:"core";s:3:"7.x";s:12:"dependencies";a:1:{i:0;s:4:"file";}s:5:"files";a:2:{i:0;s:35:"multiupload_filefield_widget.module";i:1;s:33:"multiupload_filefield_widget.test";}s:7:"version";s:8:"7.x-1.13";s:7:"project";s:28:"multiupload_filefield_widget";s:9:"datestamp";s:10:"1388873905";s:5:"mtime";i:1388873905;s:3:"php";s:5:"5.2.4";s:9:"bootstrap";i:0;}',
 ))
 ->values(array(
-  'filename' => 'sites/all/modules/contrib/multiupload_imagefield_widget/multiupload_imagefield_widget.module',
+  'filename' => 'sites/all/modules/multiupload_imagefield_widget/multiupload_imagefield_widget.module',
   'name' => 'multiupload_imagefield_widget',
   'type' => 'module',
   'owner' => '',
diff --git a/web/core/modules/migrate_drupal/tests/src/Kernel/StateFileExists.php b/web/core/modules/migrate_drupal/tests/src/Kernel/StateFileExists.php
index f2fb8607e8..6d0730dd73 100644
--- a/web/core/modules/migrate_drupal/tests/src/Kernel/StateFileExists.php
+++ b/web/core/modules/migrate_drupal/tests/src/Kernel/StateFileExists.php
@@ -99,7 +99,7 @@ public function testMigrationState() {
     foreach ($this->stateFileRequired as $module) {
       $this->assertArrayHasKey($module, $has_state_file, sprintf("Module '%s' should have a migrate_drupal.yml file", $module));
     }
-    $this->assertSame(count($this->stateFileRequired), count($has_state_file));
+    $this->assertSameSize($this->stateFileRequired, $has_state_file);
   }
 
 }
diff --git a/web/core/modules/migrate_drupal_ui/tests/src/Functional/d7/Upgrade7Test.php b/web/core/modules/migrate_drupal_ui/tests/src/Functional/d7/Upgrade7Test.php
index 667ecd5975..584dc635cb 100644
--- a/web/core/modules/migrate_drupal_ui/tests/src/Functional/d7/Upgrade7Test.php
+++ b/web/core/modules/migrate_drupal_ui/tests/src/Functional/d7/Upgrade7Test.php
@@ -83,8 +83,8 @@ protected function getEntityCounts() {
       'contact_form' => 3,
       'contact_message' => 0,
       'editor' => 2,
-      'field_config' => 89,
-      'field_storage_config' => 68,
+      'field_config' => 90,
+      'field_storage_config' => 69,
       'file' => 3,
       'filter_format' => 7,
       'image_style' => 7,
diff --git a/web/core/modules/node/migrations/state/node.migrate_drupal.yml b/web/core/modules/node/migrations/state/node.migrate_drupal.yml
index 4b7099e9e7..d3b1843fa6 100644
--- a/web/core/modules/node/migrations/state/node.migrate_drupal.yml
+++ b/web/core/modules/node/migrations/state/node.migrate_drupal.yml
@@ -1,6 +1,10 @@
 finished:
   6:
+    # Blog requires node.
+    blog: node
     content: node
     node: node
   7:
+    # Blog requires node.
+    blog: node
     node: node
diff --git a/web/core/modules/node/node.module b/web/core/modules/node/node.module
index 616d8b4de6..9099b4e12e 100644
--- a/web/core/modules/node/node.module
+++ b/web/core/modules/node/node.module
@@ -506,8 +506,8 @@ function template_preprocess_node(&$variables) {
   $variables['url'] = !$node->isNew() ? $node->toUrl('canonical')->toString() : NULL;
 
   // The 'page' variable is set to TRUE in two occasions:
-  //   - The view mode is 'full' and we are on the 'node.view' route.
-  //   - The node is in preview and view mode is either 'full' or 'default'.
+  // - The view mode is 'full' and we are on the 'node.view' route.
+  // - The node is in preview and view mode is either 'full' or 'default'.
   $variables['page'] = ($variables['view_mode'] == 'full' && (node_is_page($node)) || (isset($node->in_preview) && in_array($node->preview_view_mode, ['full', 'default'])));
 
   // Helpful $content variable for templates.
diff --git a/web/core/modules/node/src/Plugin/Block/SyndicateBlock.php b/web/core/modules/node/src/Plugin/Block/SyndicateBlock.php
index bcc98d04ba..487700f0a9 100644
--- a/web/core/modules/node/src/Plugin/Block/SyndicateBlock.php
+++ b/web/core/modules/node/src/Plugin/Block/SyndicateBlock.php
@@ -5,6 +5,7 @@
 use Drupal\Core\Access\AccessResult;
 use Drupal\Core\Block\BlockBase;
 use Drupal\Core\Session\AccountInterface;
+use Drupal\Core\Url;
 
 /**
  * Provides a 'Syndicate' block that links to the site's RSS feed.
@@ -39,7 +40,7 @@ protected function blockAccess(AccountInterface $account) {
   public function build() {
     return [
       '#theme' => 'feed_icon',
-      '#url' => 'rss.xml',
+      '#url' => Url::fromUri('internal:/rss.xml'),
     ];
   }
 
diff --git a/web/core/modules/node/src/Plugin/migrate/source/d6/Node.php b/web/core/modules/node/src/Plugin/migrate/source/d6/Node.php
index 4a4442ed8b..4fe426d890 100644
--- a/web/core/modules/node/src/Plugin/migrate/source/d6/Node.php
+++ b/web/core/modules/node/src/Plugin/migrate/source/d6/Node.php
@@ -37,7 +37,8 @@
  * In this example nodes of type page and test are retrieved from the source
  * database.
  *
- * For additional configuration keys, refer to the parent classes:
+ * For additional configuration keys, refer to the parent classes.
+ *
  * @see \Drupal\migrate\Plugin\migrate\source\SqlBase
  * @see \Drupal\migrate\Plugin\migrate\source\SourcePluginBase
  *
@@ -266,7 +267,7 @@ protected function getFieldInfo($node_type) {
    *   The node.
    *
    * @return array
-   *   The field values, keyed by delta.
+   *   The field values, keyed and sorted by delta.
    */
   protected function getFieldData(array $field, Row $node) {
     $field_table = 'content_' . $field['field_name'];
@@ -310,6 +311,7 @@ protected function getFieldData(array $field, Row $node) {
         ->isNotNull($field['field_name'] . '_' . $columns[0])
         ->condition('nid', $node->getSourceProperty('nid'))
         ->condition('vid', $node->getSourceProperty('vid'))
+        ->orderBy('delta')
         ->execute()
         ->fetchAllAssoc('delta');
     }
diff --git a/web/core/modules/node/src/Plugin/migrate/source/d6/NodeComplete.php b/web/core/modules/node/src/Plugin/migrate/source/d6/NodeComplete.php
index 96d6d29db9..c9d7f5d38b 100644
--- a/web/core/modules/node/src/Plugin/migrate/source/d6/NodeComplete.php
+++ b/web/core/modules/node/src/Plugin/migrate/source/d6/NodeComplete.php
@@ -3,7 +3,12 @@
 namespace Drupal\node\Plugin\migrate\source\d6;
 
 /**
- * Gets all node revisions from the source, including translation revisions.
+ * Drupal 6 all node revisions source, including translation revisions.
+ *
+ * For available configuration keys, refer to the parent classes.
+ *
+ * @see \Drupal\migrate\Plugin\migrate\source\SqlBase
+ * @see \Drupal\migrate\Plugin\migrate\source\SourcePluginBase
  *
  * @MigrateSource(
  *   id = "d6_node_complete",
diff --git a/web/core/modules/node/src/Plugin/migrate/source/d6/NodeRevision.php b/web/core/modules/node/src/Plugin/migrate/source/d6/NodeRevision.php
index 629249888d..a3420165e0 100644
--- a/web/core/modules/node/src/Plugin/migrate/source/d6/NodeRevision.php
+++ b/web/core/modules/node/src/Plugin/migrate/source/d6/NodeRevision.php
@@ -7,6 +7,11 @@
 /**
  * Drupal 6 node revision source from database.
  *
+ * For available configuration keys, refer to the parent classes.
+ *
+ * @see \Drupal\migrate\Plugin\migrate\source\SqlBase
+ * @see \Drupal\migrate\Plugin\migrate\source\SourcePluginBase
+ *
  * @MigrateSource(
  *   id = "d6_node_revision",
  *   source_module = "node"
diff --git a/web/core/modules/node/src/Plugin/migrate/source/d6/NodeType.php b/web/core/modules/node/src/Plugin/migrate/source/d6/NodeType.php
index 49a0e3e0ed..1238e0ee98 100644
--- a/web/core/modules/node/src/Plugin/migrate/source/d6/NodeType.php
+++ b/web/core/modules/node/src/Plugin/migrate/source/d6/NodeType.php
@@ -8,6 +8,11 @@
 /**
  * Drupal 6 Node types source from database.
  *
+ * For available configuration keys, refer to the parent classes.
+ *
+ * @see \Drupal\migrate\Plugin\migrate\source\SqlBase
+ * @see \Drupal\migrate\Plugin\migrate\source\SourcePluginBase
+ *
  * @MigrateSource(
  *   id = "d6_node_type",
  *   source_module = "node"
diff --git a/web/core/modules/node/src/Plugin/migrate/source/d6/ViewMode.php b/web/core/modules/node/src/Plugin/migrate/source/d6/ViewMode.php
index fe806489df..f5316acea5 100644
--- a/web/core/modules/node/src/Plugin/migrate/source/d6/ViewMode.php
+++ b/web/core/modules/node/src/Plugin/migrate/source/d6/ViewMode.php
@@ -3,7 +3,12 @@
 namespace Drupal\node\Plugin\migrate\source\d6;
 
 /**
- * The view mode source.
+ * Drupal 6 view mode source from database.
+ *
+ * For available configuration keys, refer to the parent classes.
+ *
+ * @see \Drupal\migrate\Plugin\migrate\source\SqlBase
+ * @see \Drupal\migrate\Plugin\migrate\source\SourcePluginBase
  *
  * @MigrateSource(
  *   id = "d6_view_mode",
diff --git a/web/core/modules/node/src/Plugin/migrate/source/d7/Node.php b/web/core/modules/node/src/Plugin/migrate/source/d7/Node.php
index 0526bba2a7..523df7e0af 100644
--- a/web/core/modules/node/src/Plugin/migrate/source/d7/Node.php
+++ b/web/core/modules/node/src/Plugin/migrate/source/d7/Node.php
@@ -37,7 +37,8 @@
  * In this example nodes of type page and test are retrieved from the source
  * database.
  *
- * For additional configuration keys, refer to the parent classes:
+ * For additional configuration keys, refer to the parent classes.
+ *
  * @see \Drupal\migrate\Plugin\migrate\source\SqlBase
  * @see \Drupal\migrate\Plugin\migrate\source\SourcePluginBase
  *
diff --git a/web/core/modules/node/src/Plugin/migrate/source/d7/NodeComplete.php b/web/core/modules/node/src/Plugin/migrate/source/d7/NodeComplete.php
index bc800ce121..24dc8b73f4 100644
--- a/web/core/modules/node/src/Plugin/migrate/source/d7/NodeComplete.php
+++ b/web/core/modules/node/src/Plugin/migrate/source/d7/NodeComplete.php
@@ -6,7 +6,12 @@
 use Drupal\migrate\Row;
 
 /**
- * Gets all node revisions from the source, including translation revisions.
+ * Drupal 7 all node revisions source, including translation revisions.
+ *
+ * For available configuration keys, refer to the parent classes.
+ *
+ * @see \Drupal\migrate\Plugin\migrate\source\SqlBase
+ * @see \Drupal\migrate\Plugin\migrate\source\SourcePluginBase
  *
  * @MigrateSource(
  *   id = "d7_node_complete",
diff --git a/web/core/modules/node/src/Plugin/migrate/source/d7/NodeEntityTranslation.php b/web/core/modules/node/src/Plugin/migrate/source/d7/NodeEntityTranslation.php
index c525f936f1..ca61c6c563 100644
--- a/web/core/modules/node/src/Plugin/migrate/source/d7/NodeEntityTranslation.php
+++ b/web/core/modules/node/src/Plugin/migrate/source/d7/NodeEntityTranslation.php
@@ -31,7 +31,8 @@
  * In this example nodes of type page and test are retrieved from the source
  * database.
  *
- * For additional configuration keys, refer to the parent classes:
+ * For additional configuration keys, refer to the parent classes.
+ *
  * @see \Drupal\migrate\Plugin\migrate\source\SqlBase
  * @see \Drupal\migrate\Plugin\migrate\source\SourcePluginBase
  *
diff --git a/web/core/modules/node/src/Plugin/migrate/source/d7/NodeRevision.php b/web/core/modules/node/src/Plugin/migrate/source/d7/NodeRevision.php
index 67071a72fc..1b13b7bbf8 100644
--- a/web/core/modules/node/src/Plugin/migrate/source/d7/NodeRevision.php
+++ b/web/core/modules/node/src/Plugin/migrate/source/d7/NodeRevision.php
@@ -5,6 +5,11 @@
 /**
  * Drupal 7 node revision source from database.
  *
+ * For available configuration keys, refer to the parent classes.
+ *
+ * @see \Drupal\migrate\Plugin\migrate\source\SqlBase
+ * @see \Drupal\migrate\Plugin\migrate\source\SourcePluginBase
+ *
  * @MigrateSource(
  *   id = "d7_node_revision",
  *   source_module = "node"
diff --git a/web/core/modules/node/src/Plugin/migrate/source/d7/NodeType.php b/web/core/modules/node/src/Plugin/migrate/source/d7/NodeType.php
index 67ac306783..1fca092801 100644
--- a/web/core/modules/node/src/Plugin/migrate/source/d7/NodeType.php
+++ b/web/core/modules/node/src/Plugin/migrate/source/d7/NodeType.php
@@ -8,6 +8,11 @@
 /**
  * Drupal 7 Node types source from database.
  *
+ * For available configuration keys, refer to the parent classes.
+ *
+ * @see \Drupal\migrate\Plugin\migrate\source\SqlBase
+ * @see \Drupal\migrate\Plugin\migrate\source\SourcePluginBase
+ *
  * @MigrateSource(
  *   id = "d7_node_type",
  *   source_module = "node"
diff --git a/web/core/modules/node/tests/src/Functional/AssertButtonsTrait.php b/web/core/modules/node/tests/src/Functional/AssertButtonsTrait.php
index 9937a8e08f..12652f8da6 100644
--- a/web/core/modules/node/tests/src/Functional/AssertButtonsTrait.php
+++ b/web/core/modules/node/tests/src/Functional/AssertButtonsTrait.php
@@ -26,8 +26,8 @@ public function assertButtons(array $buttons, $dropbutton = TRUE) {
 
       // Dropbutton elements.
       $this->assertSession()->elementsCount('xpath', '//div[@class="dropbutton-wrapper"]//input[@type="submit"]', $count);
-      for ($i = 0; $i++; $i < $count) {
-        $this->assertSession()->elementTextEquals('xpath', "(//div[@class='dropbutton-wrapper']//input[@type='submit'])[{$i + 1}]", $buttons[$i]);
+      for ($i = 1; $i++; $i <= $count) {
+        $this->assertSession()->elementTextEquals('xpath', "(//div[@class='dropbutton-wrapper']//input[@type='submit'])[$i]", $buttons[$i - 1]);
       }
     }
     else {
diff --git a/web/core/modules/node/tests/src/Functional/NodeSyndicateBlockTest.php b/web/core/modules/node/tests/src/Functional/NodeSyndicateBlockTest.php
index 4fd853ad67..0a954f8845 100644
--- a/web/core/modules/node/tests/src/Functional/NodeSyndicateBlockTest.php
+++ b/web/core/modules/node/tests/src/Functional/NodeSyndicateBlockTest.php
@@ -37,6 +37,10 @@ public function testSyndicateBlock() {
     $this->drupalPlaceBlock('node_syndicate_block', ['id' => 'test_syndicate_block']);
     $this->drupalGet('');
     $this->assertSession()->elementExists('xpath', '//div[@id="block-test-syndicate-block"]/*');
+    // Tests the syndicate block RSS link rendered at non-front pages.
+    $this->drupalGet('user');
+    $this->clickLink('Subscribe to');
+    $this->assertSession()->addressEquals('rss.xml');
   }
 
 }
diff --git a/web/core/modules/node/tests/src/Kernel/Migrate/d6/MigrateNodeCompleteTest.php b/web/core/modules/node/tests/src/Kernel/Migrate/d6/MigrateNodeCompleteTest.php
index 68f30ae936..298df46b55 100644
--- a/web/core/modules/node/tests/src/Kernel/Migrate/d6/MigrateNodeCompleteTest.php
+++ b/web/core/modules/node/tests/src/Kernel/Migrate/d6/MigrateNodeCompleteTest.php
@@ -80,6 +80,13 @@ public function testNodeCompleteMigration() {
     foreach ($this->expectedNodeFieldRevisionTable() as $key => $revision) {
       $this->assertRevision($revision, $data[$key]);
     }
+
+    // Test the order in multi-value fields.
+    $revision = $this->nodeStorage->loadRevision(21);
+    $this->assertSame([
+      ['target_id' => '15'],
+      ['target_id' => '16'],
+    ], $revision->get('field_company')->getValue());
   }
 
   /**
diff --git a/web/core/modules/node/tests/src/Kernel/Migrate/d7/MigrateNodeCompleteTest.php b/web/core/modules/node/tests/src/Kernel/Migrate/d7/MigrateNodeCompleteTest.php
index 5a6775f038..1d366d3414 100644
--- a/web/core/modules/node/tests/src/Kernel/Migrate/d7/MigrateNodeCompleteTest.php
+++ b/web/core/modules/node/tests/src/Kernel/Migrate/d7/MigrateNodeCompleteTest.php
@@ -136,6 +136,16 @@ public function testNodeCompleteMigration() {
       $this->assertSame('Bob', $revision->field_user_reference[0]->entity->getAccountName());
     }
 
+    // Test the order in multi-value fields.
+    $revision = $this->nodeStorage->loadRevision(1);
+    $this->assertSame([
+      ['value' => 'default@example.com'],
+      ['value' => 'another@example.com'],
+    ], $revision->get('field_email')->getValue());
+    $this->assertSame([
+      ['target_id' => '17'],
+      ['target_id' => '15'],
+    ], $revision->get('field_term_entityreference')->getValue());
   }
 
   /**
diff --git a/web/core/modules/node/tests/src/Kernel/NodeAccessLanguageAwareTest.php b/web/core/modules/node/tests/src/Kernel/NodeAccessLanguageAwareTest.php
index deaf02d687..7fb4067586 100644
--- a/web/core/modules/node/tests/src/Kernel/NodeAccessLanguageAwareTest.php
+++ b/web/core/modules/node/tests/src/Kernel/NodeAccessLanguageAwareTest.php
@@ -89,13 +89,13 @@ protected function setUp(): void {
 
     // Create six nodes:
     // 1. Four Hungarian nodes with Catalan translations
-    //   - One with neither language marked as private.
-    //   - One with only the Hungarian translation private.
-    //   - One with only the Catalan translation private.
-    //   - One with both the Hungarian and Catalan translations private.
+    //    - One with neither language marked as private.
+    //    - One with only the Hungarian translation private.
+    //    - One with only the Catalan translation private.
+    //    - One with both the Hungarian and Catalan translations private.
     // 2. Two nodes with no language specified.
-    //   - One public.
-    //   - One private.
+    //    - One public.
+    //    - One private.
     $this->nodes['both_public'] = $node = $this->drupalCreateNode([
       'body' => [[]],
       'langcode' => 'hu',
diff --git a/web/core/modules/node/tests/src/Kernel/NodeFieldOverridesTest.php b/web/core/modules/node/tests/src/Kernel/NodeFieldOverridesTest.php
index 4ee5a93389..ac5184735a 100644
--- a/web/core/modules/node/tests/src/Kernel/NodeFieldOverridesTest.php
+++ b/web/core/modules/node/tests/src/Kernel/NodeFieldOverridesTest.php
@@ -53,7 +53,7 @@ public function testFieldOverrides() {
     $uid_field = \Drupal::service('entity_field.manager')->getBaseFieldDefinitions('node')['uid'];
     $config = $uid_field->getConfig('ponies');
     $config->save();
-    $this->assertEquals($config->get('default_value_callback'), 'Drupal\node\Entity\Node::getDefaultEntityOwner');
+    $this->assertEquals('Drupal\node\Entity\Node::getDefaultEntityOwner', $config->get('default_value_callback'));
     /** @var \Drupal\node\NodeInterface $node */
     $node = Node::create(['type' => 'ponies']);
     $owner = $node->getOwner();
diff --git a/web/core/modules/path/src/Plugin/migrate/source/d6/UrlAlias.php b/web/core/modules/path/src/Plugin/migrate/source/d6/UrlAlias.php
index c01d364733..812e0985d2 100644
--- a/web/core/modules/path/src/Plugin/migrate/source/d6/UrlAlias.php
+++ b/web/core/modules/path/src/Plugin/migrate/source/d6/UrlAlias.php
@@ -5,7 +5,12 @@
 use Drupal\path\Plugin\migrate\source\UrlAliasBase;
 
 /**
- * URL aliases source from database.
+ * Drupal 6 URL aliases source from database.
+ *
+ * For available configuration keys, refer to the parent classes.
+ *
+ * @see \Drupal\migrate\Plugin\migrate\source\SqlBase
+ * @see \Drupal\migrate\Plugin\migrate\source\SourcePluginBase
  *
  * @MigrateSource(
  *   id = "d6_url_alias",
diff --git a/web/core/modules/path/src/Plugin/migrate/source/d7/UrlAlias.php b/web/core/modules/path/src/Plugin/migrate/source/d7/UrlAlias.php
index 58405fdf19..4aebd3b95b 100644
--- a/web/core/modules/path/src/Plugin/migrate/source/d7/UrlAlias.php
+++ b/web/core/modules/path/src/Plugin/migrate/source/d7/UrlAlias.php
@@ -5,7 +5,12 @@
 use Drupal\path\Plugin\migrate\source\UrlAliasBase;
 
 /**
- * URL aliases source from database.
+ * Drupal 7 URL aliases source from database.
+ *
+ * For available configuration keys, refer to the parent classes.
+ *
+ * @see \Drupal\migrate\Plugin\migrate\source\SqlBase
+ * @see \Drupal\migrate\Plugin\migrate\source\SourcePluginBase
  *
  * @MigrateSource(
  *   id = "d7_url_alias",
diff --git a/web/core/modules/path_alias/tests/src/Kernel/AliasTest.php b/web/core/modules/path_alias/tests/src/Kernel/AliasTest.php
index bcf7da6327..d78ad96f96 100644
--- a/web/core/modules/path_alias/tests/src/Kernel/AliasTest.php
+++ b/web/core/modules/path_alias/tests/src/Kernel/AliasTest.php
@@ -194,7 +194,7 @@ public function testWhitelistCacheDeletionMidRequest() {
 
     // Destruct the whitelist so it persists its cache.
     $whitelist->destruct();
-    $this->assertEquals($memoryCounterBackend->getCounter('set', 'path_alias_whitelist'), 1);
+    $this->assertEquals(1, $memoryCounterBackend->getCounter('set', 'path_alias_whitelist'));
     // Cache data should have data for 'user' and 'admin', even though just
     // 'admin' was looked up. This is because the cache is primed with all
     // menu router base paths.
@@ -217,7 +217,7 @@ public function testWhitelistCacheDeletionMidRequest() {
     // from underneath it and not save anything to cache, to protect from
     // cache corruption.
     $whitelist->destruct();
-    $this->assertEquals($memoryCounterBackend->getCounter('set', 'path_alias_whitelist'), 0);
+    $this->assertEquals(0, $memoryCounterBackend->getCounter('set', 'path_alias_whitelist'));
     $this->assertFalse($memoryCounterBackend->get('path_alias_whitelist'));
     $memoryCounterBackend->resetCounter();
   }
diff --git a/web/core/modules/rdf/src/Plugin/migrate/source/d7/RdfMapping.php b/web/core/modules/rdf/src/Plugin/migrate/source/d7/RdfMapping.php
index f8e613ae21..282d35f0c5 100644
--- a/web/core/modules/rdf/src/Plugin/migrate/source/d7/RdfMapping.php
+++ b/web/core/modules/rdf/src/Plugin/migrate/source/d7/RdfMapping.php
@@ -8,6 +8,11 @@
 /**
  * Drupal 7 rdf source from database.
  *
+ * For available configuration keys, refer to the parent classes.
+ *
+ * @see \Drupal\migrate\Plugin\migrate\source\SqlBase
+ * @see \Drupal\migrate\Plugin\migrate\source\SourcePluginBase
+ *
  * @MigrateSource(
  *   id = "d7_rdf_mapping",
  *   source_module = "rdf"
diff --git a/web/core/modules/rdf/tests/src/Unit/RdfMappingConfigEntityUnitTest.php b/web/core/modules/rdf/tests/src/Unit/RdfMappingConfigEntityUnitTest.php
index 805714dbdc..1df305686f 100644
--- a/web/core/modules/rdf/tests/src/Unit/RdfMappingConfigEntityUnitTest.php
+++ b/web/core/modules/rdf/tests/src/Unit/RdfMappingConfigEntityUnitTest.php
@@ -81,18 +81,13 @@ public function testCalculateDependencies() {
       ->method('getBundleConfigDependency')
       ->will($this->returnValue(['type' => 'module', 'name' => 'test_module']));
 
-    $this->entityTypeManager->expects($this->at(0))
+    $this->entityTypeManager->expects($this->any())
       ->method('getDefinition')
-      ->with($target_entity_type_id)
-      ->will($this->returnValue($target_entity_type));
-    $this->entityTypeManager->expects($this->at(1))
-      ->method('getDefinition')
-      ->with($this->entityTypeId)
-      ->will($this->returnValue($this->entityType));
-    $this->entityTypeManager->expects($this->at(2))
-      ->method('getDefinition')
-      ->with($this->entityTypeId)
-      ->will($this->returnValue($this->entityType));
+      ->willReturnMap([
+        [$target_entity_type_id, TRUE, $target_entity_type],
+        [$this->entityTypeId, TRUE, $this->entityType],
+      ]);
+
     $entity = new RdfMapping($values, $this->entityTypeId);
     $dependencies = $entity->calculateDependencies()->getDependencies();
     $this->assertArrayNotHasKey('config', $dependencies);
@@ -115,14 +110,12 @@ public function testCalculateDependenciesWithEntityBundle() {
       ->method('getBundleConfigDependency')
       ->will($this->returnValue(['type' => 'config', 'name' => 'test_module.type.' . $bundle_id]));
 
-    $this->entityTypeManager->expects($this->at(0))
-      ->method('getDefinition')
-      ->with($target_entity_type_id)
-      ->will($this->returnValue($target_entity_type));
-    $this->entityTypeManager->expects($this->at(1))
+    $this->entityTypeManager->expects($this->any())
       ->method('getDefinition')
-      ->with($this->entityTypeId)
-      ->will($this->returnValue($this->entityType));
+      ->willReturnMap([
+        [$target_entity_type_id, TRUE, $target_entity_type],
+        [$this->entityTypeId, TRUE, $this->entityType],
+      ]);
 
     $entity = new RdfMapping($values, $this->entityTypeId);
     $dependencies = $entity->calculateDependencies()->getDependencies();
diff --git a/web/core/modules/rest/tests/src/Unit/CollectRoutesTest.php b/web/core/modules/rest/tests/src/Unit/CollectRoutesTest.php
index a53caf9cc3..4ede3332a4 100644
--- a/web/core/modules/rest/tests/src/Unit/CollectRoutesTest.php
+++ b/web/core/modules/rest/tests/src/Unit/CollectRoutesTest.php
@@ -155,7 +155,7 @@ public function testRoutesRequirements() {
     // Check auth options.
     $auth = $this->routes->get('view.test_view.page_1')->getOption('_auth');
     $this->assertCount(1, $auth, 'View route with rest export has an auth option added');
-    $this->assertEquals($auth[0], 'basic_auth', 'View route with rest export has the correct auth option added');
+    $this->assertEquals('basic_auth', $auth[0], 'View route with rest export has the correct auth option added');
   }
 
 }
diff --git a/web/core/modules/search/src/Plugin/migrate/source/d6/SearchPage.php b/web/core/modules/search/src/Plugin/migrate/source/d6/SearchPage.php
index 085de33f17..81b27271f6 100644
--- a/web/core/modules/search/src/Plugin/migrate/source/d6/SearchPage.php
+++ b/web/core/modules/search/src/Plugin/migrate/source/d6/SearchPage.php
@@ -5,7 +5,13 @@
 use Drupal\migrate_drupal\Plugin\migrate\source\Variable;
 
 /**
- * Get node search rankings for core modules.
+ * Drupal 6 node search rankings for core modules source from database.
+ *
+ * For available configuration keys, refer to the parent classes.
+ *
+ * @see \Drupal\migrate_drupal\Plugin\migrate\source\Variable
+ * @see \Drupal\migrate\Plugin\migrate\source\SqlBase
+ * @see \Drupal\migrate\Plugin\migrate\source\SourcePluginBase
  *
  * @MigrateSource(
  *   id = "d6_search_page",
diff --git a/web/core/modules/search/src/Plugin/migrate/source/d7/SearchPage.php b/web/core/modules/search/src/Plugin/migrate/source/d7/SearchPage.php
index 6ae2b22c38..079bfaeb7e 100644
--- a/web/core/modules/search/src/Plugin/migrate/source/d7/SearchPage.php
+++ b/web/core/modules/search/src/Plugin/migrate/source/d7/SearchPage.php
@@ -6,7 +6,13 @@
 use Drupal\migrate_drupal\Plugin\migrate\source\Variable;
 
 /**
- * Get search_active_modules and rankings for core modules.
+ * Drupal 7 search active core modules and rankings source from database.
+ *
+ * For available configuration keys, refer to the parent classes.
+ *
+ * @see \Drupal\migrate_drupal\Plugin\migrate\source\Variable
+ * @see \Drupal\migrate\Plugin\migrate\source\SqlBase
+ * @see \Drupal\migrate\Plugin\migrate\source\SourcePluginBase
  *
  * @MigrateSource(
  *   id = "d7_search_page",
diff --git a/web/core/modules/search/tests/src/Kernel/SearchMatchTest.php b/web/core/modules/search/tests/src/Kernel/SearchMatchTest.php
index 511c0ef678..9ec5853f72 100644
--- a/web/core/modules/search/tests/src/Kernel/SearchMatchTest.php
+++ b/web/core/modules/search/tests/src/Kernel/SearchMatchTest.php
@@ -108,9 +108,9 @@ public function _testQueries() {
     // Note: OR queries that include short words in OR groups are only accepted
     // if the ORed terms are ANDed with at least one long word in the rest of
     // the query. Examples:
-    //   enim dolore OR ut = enim (dolore OR ut) = (enim dolor) OR (enim ut)
+    // -  enim dolore OR ut = enim (dolore OR ut) = (enim dolor) OR (enim ut)
     // is good, and
-    //   dolore OR ut = (dolore) OR (ut)
+    // -  dolore OR ut = (dolore) OR (ut)
     // is bad. This is a design limitation to avoid full table scans.
     $queries = [
       // Simple AND queries.
diff --git a/web/core/modules/serialization/src/Normalizer/SerializedColumnNormalizerTrait.php b/web/core/modules/serialization/src/Normalizer/SerializedColumnNormalizerTrait.php
index bf6eb0643c..0b740dd3e5 100644
--- a/web/core/modules/serialization/src/Normalizer/SerializedColumnNormalizerTrait.php
+++ b/web/core/modules/serialization/src/Normalizer/SerializedColumnNormalizerTrait.php
@@ -23,11 +23,11 @@ trait SerializedColumnNormalizerTrait {
   protected function checkForSerializedStrings($data, $class, FieldItemInterface $field_item) {
     // Require specialized denormalizers for fields with 'serialize' columns.
     // Note: this cannot be checked in ::supportsDenormalization() because at
-    //       that time we only have the field item class. ::hasSerializeColumn()
-    //       must be able to call $field_item->schema(), which requires a field
-    //       storage definition. To determine that, the entity type and bundle
-    //       must be known, which is contextual information that the Symfony
-    //       serializer does not pass to ::supportsDenormalization().
+    // that time we only have the field item class. ::hasSerializeColumn()
+    // must be able to call $field_item->schema(), which requires a field
+    // storage definition. To determine that, the entity type and bundle
+    // must be known, which is contextual information that the Symfony
+    // serializer does not pass to ::supportsDenormalization().
     if (!is_array($data)) {
       $data = [$field_item->getDataDefinition()->getMainPropertyName() => $data];
     }
diff --git a/web/core/modules/serialization/tests/src/Kernel/EntitySerializationTest.php b/web/core/modules/serialization/tests/src/Kernel/EntitySerializationTest.php
index 16353354fb..2a09246428 100644
--- a/web/core/modules/serialization/tests/src/Kernel/EntitySerializationTest.php
+++ b/web/core/modules/serialization/tests/src/Kernel/EntitySerializationTest.php
@@ -295,7 +295,7 @@ public function testDenormalizeSerializedItem() {
   public function testDenormalizeCustomSerializedItem() {
     $entity = EntitySerializedField::create(['serialized_text' => serialize(['Hello world!'])]);
     $normalized = $this->serializer->normalize($entity);
-    $this->assertEquals($normalized['serialized_text'][0]['value'], ['Hello world!']);
+    $this->assertEquals(['Hello world!'], $normalized['serialized_text'][0]['value']);
     $this->expectException(\LogicException::class);
     $this->expectExceptionMessage('The generic FieldItemNormalizer cannot denormalize string values for "value" properties of the "serialized_text" field (field item class: Drupal\entity_test\Plugin\Field\FieldType\SerializedPropertyItem).');
     $this->serializer->denormalize([
@@ -314,7 +314,7 @@ public function testDenormalizeCustomSerializedItem() {
   public function testDenormalizeInvalidCustomSerializedField() {
     $entity = EntitySerializedField::create(['serialized_long' => serialize(['Hello world!'])]);
     $normalized = $this->serializer->normalize($entity);
-    $this->assertEquals($normalized['serialized_long'][0]['value'], ['Hello world!']);
+    $this->assertEquals(['Hello world!'], $normalized['serialized_long'][0]['value']);
     $this->expectException(\LogicException::class);
     $this->expectExceptionMessage('The generic FieldItemNormalizer cannot denormalize string values for "value" properties of the "serialized_long" field (field item class: Drupal\Core\Field\Plugin\Field\FieldType\StringLongItem).');
     $this->serializer->denormalize([
diff --git a/web/core/modules/serialization/tests/src/Unit/Normalizer/EntityNormalizerTest.php b/web/core/modules/serialization/tests/src/Unit/Normalizer/EntityNormalizerTest.php
index 640a340204..fbe0c2edd3 100644
--- a/web/core/modules/serialization/tests/src/Unit/Normalizer/EntityNormalizerTest.php
+++ b/web/core/modules/serialization/tests/src/Unit/Normalizer/EntityNormalizerTest.php
@@ -93,12 +93,12 @@ public function testNormalize() {
       ->disableOriginalConstructor()
       ->setMethods(['normalize'])
       ->getMock();
-    $serializer->expects($this->at(0))
+    $serializer->expects($this->exactly(2))
       ->method('normalize')
-      ->with($list_item_1, 'test_format');
-    $serializer->expects($this->at(1))
-      ->method('normalize')
-      ->with($list_item_2, 'test_format');
+      ->withConsecutive(
+        [$list_item_1, 'test_format'],
+        [$list_item_2, 'test_format'],
+      );
 
     $this->entityNormalizer->setSerializer($serializer);
 
@@ -165,11 +165,11 @@ public function testDenormalizeWithValidBundle() {
       'test_type' => $entity_type_definition,
     ];
 
-    $this->entityTypeManager->expects($this->at(0))
+    $this->entityTypeManager->expects($this->once())
       ->method('getDefinition')
       ->with('test')
       ->will($this->returnValue($entity_type));
-    $this->entityFieldManager->expects($this->at(0))
+    $this->entityFieldManager->expects($this->once())
       ->method('getBaseFieldDefinitions')
       ->with('test')
       ->will($this->returnValue($base_definitions));
@@ -184,23 +184,16 @@ public function testDenormalizeWithValidBundle() {
       ->method('getQuery')
       ->will($this->returnValue($entity_query_mock));
 
-    $this->entityTypeManager->expects($this->at(1))
-      ->method('getStorage')
-      ->with('test_bundle')
-      ->will($this->returnValue($entity_type_storage));
-
     $key_1 = $this->createMock(FieldItemListInterface::class);
     $key_2 = $this->createMock(FieldItemListInterface::class);
 
     $entity = $this->createMock(FieldableEntityInterface::class);
-    $entity->expects($this->at(0))
-      ->method('get')
-      ->with('key_1')
-      ->willReturn($key_1);
-    $entity->expects($this->at(1))
+    $entity->expects($this->exactly(2))
       ->method('get')
-      ->with('key_2')
-      ->willReturn($key_2);
+      ->willReturnMap([
+        ['key_1', $key_1],
+        ['key_2', $key_2],
+      ]);
 
     $storage = $this->createMock('Drupal\Core\Entity\EntityStorageInterface');
     // Create should only be called with the bundle property at first.
@@ -213,10 +206,12 @@ public function testDenormalizeWithValidBundle() {
       ->with($expected_test_data)
       ->will($this->returnValue($entity));
 
-    $this->entityTypeManager->expects($this->at(2))
+    $this->entityTypeManager->expects($this->exactly(2))
       ->method('getStorage')
-      ->with('test')
-      ->will($this->returnValue($storage));
+      ->willReturnMap([
+        ['test_bundle', $entity_type_storage],
+        ['test', $storage],
+      ]);
 
     // Setup expectations for the serializer. This will be called for each field
     // item.
@@ -224,12 +219,12 @@ public function testDenormalizeWithValidBundle() {
       ->disableOriginalConstructor()
       ->setMethods(['denormalize'])
       ->getMock();
-    $serializer->expects($this->at(0))
+    $serializer->expects($this->exactly(2))
       ->method('denormalize')
-      ->with('value_1', get_class($key_1), NULL, ['target_instance' => $key_1, 'entity_type' => 'test']);
-    $serializer->expects($this->at(1))
-      ->method('denormalize')
-      ->with('value_2', get_class($key_2), NULL, ['target_instance' => $key_2, 'entity_type' => 'test']);
+      ->withConsecutive(
+        ['value_1', get_class($key_1), NULL, ['target_instance' => $key_1, 'entity_type' => 'test']],
+        ['value_2', get_class($key_2), NULL, ['target_instance' => $key_2, 'entity_type' => 'test']],
+      );
 
     $this->entityNormalizer->setSerializer($serializer);
 
@@ -286,11 +281,11 @@ public function testDenormalizeWithInvalidBundle() {
       'test_type' => $entity_type_definition,
     ];
 
-    $this->entityTypeManager->expects($this->at(0))
+    $this->entityTypeManager->expects($this->once())
       ->method('getDefinition')
       ->with('test')
       ->will($this->returnValue($entity_type));
-    $this->entityFieldManager->expects($this->at(0))
+    $this->entityFieldManager->expects($this->once())
       ->method('getBaseFieldDefinitions')
       ->with('test')
       ->will($this->returnValue($base_definitions));
@@ -305,7 +300,7 @@ public function testDenormalizeWithInvalidBundle() {
       ->method('getQuery')
       ->will($this->returnValue($entity_query_mock));
 
-    $this->entityTypeManager->expects($this->at(1))
+    $this->entityTypeManager->expects($this->once())
       ->method('getStorage')
       ->with('test_bundle')
       ->will($this->returnValue($entity_type_storage));
@@ -346,14 +341,12 @@ public function testDenormalizeWithNoBundle() {
     $key_2 = $this->createMock(FieldItemListInterface::class);
 
     $entity = $this->createMock(FieldableEntityInterface::class);
-    $entity->expects($this->at(0))
-      ->method('get')
-      ->with('key_1')
-      ->willReturn($key_1);
-    $entity->expects($this->at(1))
+    $entity->expects($this->exactly(2))
       ->method('get')
-      ->with('key_2')
-      ->willReturn($key_2);
+      ->willReturnMap([
+        ['key_1', $key_1],
+        ['key_2', $key_2],
+      ]);
 
     $storage = $this->createMock('Drupal\Core\Entity\EntityStorageInterface');
     $storage->expects($this->once())
@@ -375,12 +368,12 @@ public function testDenormalizeWithNoBundle() {
       ->disableOriginalConstructor()
       ->setMethods(['denormalize'])
       ->getMock();
-    $serializer->expects($this->at(0))
-      ->method('denormalize')
-      ->with('value_1', get_class($key_1), NULL, ['target_instance' => $key_1, 'entity_type' => 'test']);
-    $serializer->expects($this->at(1))
+    $serializer->expects($this->exactly(2))
       ->method('denormalize')
-      ->with('value_2', get_class($key_2), NULL, ['target_instance' => $key_2, 'entity_type' => 'test']);
+      ->withConsecutive(
+        ['value_1', get_class($key_1), NULL, ['target_instance' => $key_1, 'entity_type' => 'test']],
+        ['value_2', get_class($key_2), NULL, ['target_instance' => $key_2, 'entity_type' => 'test']],
+      );
 
     $this->entityNormalizer->setSerializer($serializer);
 
diff --git a/web/core/modules/settings_tray/tests/src/FunctionalJavascript/SettingsTrayBlockFormTest.php b/web/core/modules/settings_tray/tests/src/FunctionalJavascript/SettingsTrayBlockFormTest.php
index 7ece59ef94..4f7c880bed 100644
--- a/web/core/modules/settings_tray/tests/src/FunctionalJavascript/SettingsTrayBlockFormTest.php
+++ b/web/core/modules/settings_tray/tests/src/FunctionalJavascript/SettingsTrayBlockFormTest.php
@@ -99,9 +99,9 @@ protected function doTestBlocks($theme, $block_plugin, $new_page_text, $element_
         // Confirm "Display Title" is not checked.
         $web_assert->checkboxNotChecked('settings[label_display]');
         // Confirm Title is not visible.
-        $this->assertEquals($this->isLabelInputVisible(), FALSE, 'Label is not visible');
+        $this->assertFalse($this->isLabelInputVisible(), 'Label is not visible');
         $page->checkField('settings[label_display]');
-        $this->assertEquals($this->isLabelInputVisible(), TRUE, 'Label is visible');
+        $this->assertTrue($this->isLabelInputVisible(), 'Label is visible');
         // Fill out form, save the form.
         $page->fillField('settings[label]', $new_page_text);
 
diff --git a/web/core/modules/settings_tray/tests/src/FunctionalJavascript/SettingsTrayTestBase.php b/web/core/modules/settings_tray/tests/src/FunctionalJavascript/SettingsTrayTestBase.php
index 63692e954b..29ed1541dd 100644
--- a/web/core/modules/settings_tray/tests/src/FunctionalJavascript/SettingsTrayTestBase.php
+++ b/web/core/modules/settings_tray/tests/src/FunctionalJavascript/SettingsTrayTestBase.php
@@ -137,11 +137,11 @@ protected function assertOffCanvasBlockFormIsValid() {
     $web_assert->elementTextContains('css', '.form-item-settings-label-display label', 'Display block title');
     // Confirm Block title label is shown if checkbox is checked.
     if ($this->getSession()->getPage()->find('css', 'input[name="settings[label_display]"]')->isChecked()) {
-      $this->assertEquals($this->isLabelInputVisible(), TRUE, 'Label is visible');
+      $this->assertTrue($this->isLabelInputVisible(), 'Label is visible');
       $web_assert->elementTextContains('css', '.form-item-settings-label label', 'Block title');
     }
     else {
-      $this->assertEquals($this->isLabelInputVisible(), FALSE, 'Label is not visible');
+      $this->assertFalse($this->isLabelInputVisible(), 'Label is not visible');
     }
 
     // Check that common block form elements exist.
diff --git a/web/core/modules/shortcut/src/Plugin/migrate/source/d7/Shortcut.php b/web/core/modules/shortcut/src/Plugin/migrate/source/d7/Shortcut.php
index adf37f92cd..2ddbdcf7fa 100644
--- a/web/core/modules/shortcut/src/Plugin/migrate/source/d7/Shortcut.php
+++ b/web/core/modules/shortcut/src/Plugin/migrate/source/d7/Shortcut.php
@@ -7,6 +7,11 @@
 /**
  * Drupal 7 shortcut links source from database.
  *
+ * For available configuration keys, refer to the parent classes.
+ *
+ * @see \Drupal\migrate\Plugin\migrate\source\SqlBase
+ * @see \Drupal\migrate\Plugin\migrate\source\SourcePluginBase
+ *
  * @MigrateSource(
  *   id = "d7_shortcut",
  *   source_module = "shortcut"
diff --git a/web/core/modules/shortcut/src/Plugin/migrate/source/d7/ShortcutSet.php b/web/core/modules/shortcut/src/Plugin/migrate/source/d7/ShortcutSet.php
index 7a3ed8ac53..0250a24de9 100644
--- a/web/core/modules/shortcut/src/Plugin/migrate/source/d7/ShortcutSet.php
+++ b/web/core/modules/shortcut/src/Plugin/migrate/source/d7/ShortcutSet.php
@@ -7,6 +7,11 @@
 /**
  * Drupal 7 shortcut_set source from database.
  *
+ * For available configuration keys, refer to the parent classes.
+ *
+ * @see \Drupal\migrate\Plugin\migrate\source\SqlBase
+ * @see \Drupal\migrate\Plugin\migrate\source\SourcePluginBase
+ *
  * @MigrateSource(
  *   id = "d7_shortcut_set",
  *   source_module = "shortcut"
diff --git a/web/core/modules/shortcut/src/Plugin/migrate/source/d7/ShortcutSetUsers.php b/web/core/modules/shortcut/src/Plugin/migrate/source/d7/ShortcutSetUsers.php
index c4d54e9fd0..a18cbe6c00 100644
--- a/web/core/modules/shortcut/src/Plugin/migrate/source/d7/ShortcutSetUsers.php
+++ b/web/core/modules/shortcut/src/Plugin/migrate/source/d7/ShortcutSetUsers.php
@@ -7,6 +7,11 @@
 /**
  * Drupal 7 shortcut_set_users source from database.
  *
+ * For available configuration keys, refer to the parent classes.
+ *
+ * @see \Drupal\migrate\Plugin\migrate\source\SqlBase
+ * @see \Drupal\migrate\Plugin\migrate\source\SourcePluginBase
+ *
  * @MigrateSource(
  *   id = "d7_shortcut_set_users",
  *   source_module = "shortcut"
diff --git a/web/core/modules/statistics/src/Plugin/migrate/source/NodeCounter.php b/web/core/modules/statistics/src/Plugin/migrate/source/NodeCounter.php
index 0877d3fbd5..4309718a83 100644
--- a/web/core/modules/statistics/src/Plugin/migrate/source/NodeCounter.php
+++ b/web/core/modules/statistics/src/Plugin/migrate/source/NodeCounter.php
@@ -5,7 +5,12 @@
 use Drupal\migrate_drupal\Plugin\migrate\source\DrupalSqlBase;
 
 /**
- * Node counter source from database.
+ * Drupal 6/7 node counter source from database.
+ *
+ * For available configuration keys, refer to the parent classes.
+ *
+ * @see \Drupal\migrate\Plugin\migrate\source\SqlBase
+ * @see \Drupal\migrate\Plugin\migrate\source\SourcePluginBase
  *
  * @MigrateSource(
  *   id = "node_counter",
diff --git a/web/core/modules/system/src/Plugin/migrate/source/Extension.php b/web/core/modules/system/src/Plugin/migrate/source/Extension.php
index 379939110d..cc40dc7154 100644
--- a/web/core/modules/system/src/Plugin/migrate/source/Extension.php
+++ b/web/core/modules/system/src/Plugin/migrate/source/Extension.php
@@ -6,7 +6,28 @@
 use Drupal\migrate_drupal\Plugin\migrate\source\DrupalSqlBase;
 
 /**
- * Gets system data for a legacy extension.
+ * Drupal 6/7 system data for a legacy extension source from database.
+ *
+ * Available configuration keys:
+ * - name: (optional) The extension name to filter items retrieved from the
+ *   source - can be a string or an array. If omitted, all extensions are
+ *   retrieved.
+ *
+ * Examples:
+ *
+ * @code
+ * source:
+ *   plugin: extension
+ *   name: node
+ * @endcode
+ *
+ * In this example the system data for node module is retrieved from the source
+ * database.
+ *
+ * For additional configuration keys, refer to the parent classes.
+ *
+ * @see \Drupal\migrate\Plugin\migrate\source\SqlBase
+ * @see \Drupal\migrate\Plugin\migrate\source\SourcePluginBase
  *
  * @MigrateSource(
  *   id = "extension",
diff --git a/web/core/modules/system/src/Plugin/migrate/source/Menu.php b/web/core/modules/system/src/Plugin/migrate/source/Menu.php
index 14296f1ade..2e57e6eaa3 100644
--- a/web/core/modules/system/src/Plugin/migrate/source/Menu.php
+++ b/web/core/modules/system/src/Plugin/migrate/source/Menu.php
@@ -5,7 +5,12 @@
 use Drupal\migrate_drupal\Plugin\migrate\source\DrupalSqlBase;
 
 /**
- * Menu source from database.
+ * Drupal 6/7 menu source from database.
+ *
+ * For available configuration keys, refer to the parent classes.
+ *
+ * @see \Drupal\migrate\Plugin\migrate\source\SqlBase
+ * @see \Drupal\migrate\Plugin\migrate\source\SourcePluginBase
  *
  * @MigrateSource(
  *   id = "menu",
diff --git a/web/core/modules/system/src/Plugin/migrate/source/d7/MenuTranslation.php b/web/core/modules/system/src/Plugin/migrate/source/d7/MenuTranslation.php
index 623d58462a..1074d7e74a 100644
--- a/web/core/modules/system/src/Plugin/migrate/source/d7/MenuTranslation.php
+++ b/web/core/modules/system/src/Plugin/migrate/source/d7/MenuTranslation.php
@@ -5,7 +5,12 @@
 use Drupal\system\Plugin\migrate\source\Menu;
 
 /**
- * Menu translation source from database.
+ * Drupal 7 i18n menu translation source from database.
+ *
+ * For available configuration keys, refer to the parent classes.
+ *
+ * @see \Drupal\migrate\Plugin\migrate\source\SqlBase
+ * @see \Drupal\migrate\Plugin\migrate\source\SourcePluginBase
  *
  * @MigrateSource(
  *   id = "d7_menu_translation",
diff --git a/web/core/modules/system/src/Plugin/migrate/source/d7/ThemeSettings.php b/web/core/modules/system/src/Plugin/migrate/source/d7/ThemeSettings.php
index 6ae17beabe..31cb3c0b94 100644
--- a/web/core/modules/system/src/Plugin/migrate/source/d7/ThemeSettings.php
+++ b/web/core/modules/system/src/Plugin/migrate/source/d7/ThemeSettings.php
@@ -5,7 +5,13 @@
 use Drupal\migrate_drupal\Plugin\migrate\source\VariableMultiRow;
 
 /**
- * Drupal 7 system source from database.
+ * Drupal 7 theme settings source from database.
+ *
+ * For available configuration keys, refer to the parent classes.
+ *
+ * @see \Drupal\migrate_drupal\Plugin\migrate\source\VariableMultiRow
+ * @see \Drupal\migrate\Plugin\migrate\source\SqlBase
+ * @see \Drupal\migrate\Plugin\migrate\source\SourcePluginBase
  *
  * @MigrateSource(
  *   id = "d7_theme_settings",
diff --git a/web/core/modules/system/tests/modules/entity_test/entity_test.module b/web/core/modules/system/tests/modules/entity_test/entity_test.module
index af58b40f13..1b77226d17 100644
--- a/web/core/modules/system/tests/modules/entity_test/entity_test.module
+++ b/web/core/modules/system/tests/modules/entity_test/entity_test.module
@@ -175,7 +175,7 @@ function entity_test_entity_base_field_info_alter(&$fields, EntityTypeInterface
   // In 8001 we are assuming that a new definition with multiple cardinality has
   // been deployed.
   // @todo Remove this if we end up using state definitions at runtime. See
-  //    https://www.drupal.org/node/2554235.
+  //   https://www.drupal.org/node/2554235.
   if ($entity_type->id() == 'entity_test' && $state->get('entity_test.db_updates.entity_definition_updates') == 8001) {
     $fields['user_id']->setCardinality(FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED);
   }
diff --git a/web/core/modules/system/tests/modules/module_test/module_test.services.yml b/web/core/modules/system/tests/modules/module_test/module_test.services.yml
new file mode 100644
index 0000000000..58fe6bf765
--- /dev/null
+++ b/web/core/modules/system/tests/modules/module_test/module_test.services.yml
@@ -0,0 +1,7 @@
+services:
+  # Tests module uninstall
+  plugin.manager.module_test.cache_clear_test:
+    class: Drupal\module_test\PluginManagerCacheClearer
+    arguments: ['@state', '@?logger.dblog']
+    tags:
+      - { name: plugin_manager_cache_clear }
diff --git a/web/core/modules/system/tests/modules/module_test/src/PluginManagerCacheClearer.php b/web/core/modules/system/tests/modules/module_test/src/PluginManagerCacheClearer.php
new file mode 100644
index 0000000000..fbfb4fed8c
--- /dev/null
+++ b/web/core/modules/system/tests/modules/module_test/src/PluginManagerCacheClearer.php
@@ -0,0 +1,47 @@
+<?php
+
+namespace Drupal\module_test;
+
+use Drupal\Core\Plugin\DefaultPluginManager;
+use Drupal\Core\State\StateInterface;
+
+/**
+ * Helps test module uninstall.
+ */
+class PluginManagerCacheClearer extends DefaultPluginManager {
+
+  /**
+   * @var \Drupal\Core\State\StateInterface
+   */
+  protected $state;
+
+  /**
+   * An optional service dependency.
+   *
+   * @var object|null
+   */
+  protected $optionalService;
+
+  /**
+   * PluginManagerCacheClearer constructor.
+   *
+   * @param \Drupal\Core\State\StateInterface $state
+   *   The state service for recording what happens.
+   * @param null $optional_service
+   *   An optional service for testing.
+   */
+  public function __construct(StateInterface $state, $optional_service = NULL) {
+    $this->state = $state;
+    $this->optionalService = $optional_service;
+  }
+
+  /**
+   * Tests call to CachedDiscoveryInterface::clearCachedDefinitions().
+   *
+   * @see \Drupal\Component\Plugin\Discovery\CachedDiscoveryInterface::clearCachedDefinitions()
+   */
+  public function clearCachedDefinitions() {
+    $this->state->set(self::class, isset($this->optionalService));
+  }
+
+}
diff --git a/web/core/modules/system/tests/modules/plugin_test/src/Plugin/MockBlockManager.php b/web/core/modules/system/tests/modules/plugin_test/src/Plugin/MockBlockManager.php
index ef8d6c4790..766aa7a8d5 100644
--- a/web/core/modules/system/tests/modules/plugin_test/src/Plugin/MockBlockManager.php
+++ b/web/core/modules/system/tests/modules/plugin_test/src/Plugin/MockBlockManager.php
@@ -138,7 +138,7 @@ public function __construct() {
    */
   protected function createContextDefinition($data_type, $label, $required = TRUE) {
     // We cast the label to string for testing purposes only, as it may be
-    // a TranslatableMarkup and we will do assertEqual() checks on arrays that
+    // a TranslatableMarkup and we will do assertEquals() checks on arrays that
     // include ContextDefinition objects, and var_export() has problems
     // printing TranslatableMarkup objects.
     $class = ContextDefinition::class;
diff --git a/web/core/modules/system/tests/src/Functional/Form/ElementsLabelsTest.php b/web/core/modules/system/tests/src/Functional/Form/ElementsLabelsTest.php
index 3ef3609476..4eb3d96fb7 100644
--- a/web/core/modules/system/tests/src/Functional/Form/ElementsLabelsTest.php
+++ b/web/core/modules/system/tests/src/Functional/Form/ElementsLabelsTest.php
@@ -48,8 +48,9 @@ public function testFormLabels() {
 
     // Exercise various defaults for textboxes and modifications to ensure
     // appropriate override and correct behavior.
-    $elements = $this->xpath('//label[@for="edit-form-textfield-test-title-and-required" and @class="js-form-required form-required"]/following-sibling::input[@id="edit-form-textfield-test-title-and-required"]');
-    $this->assertTrue(isset($elements[0]), 'Label precedes textfield, with required marker inside label.');
+
+    // Verify that label precedes textfield, with required marker inside label.
+    $this->assertSession()->elementExists('xpath', '//label[@for="edit-form-textfield-test-title-and-required" and @class="js-form-required form-required"]/following-sibling::input[@id="edit-form-textfield-test-title-and-required"]');
 
     $this->assertSession()->elementExists('xpath', '//input[@id="edit-form-textfield-test-no-title-required"]/preceding-sibling::label[@for="edit-form-textfield-test-no-title-required" and @class="js-form-required form-required"]');
     $this->assertSession()->elementExists('xpath', '//input[@id="edit-form-textfield-test-title-invisible"]/preceding-sibling::label[@for="edit-form-textfield-test-title-invisible" and @class="visually-hidden"]');
@@ -58,8 +59,8 @@ public function testFormLabels() {
 
     $this->assertSession()->elementExists('xpath', '//input[@id="edit-form-textfield-test-title-after"]/following-sibling::label[@for="edit-form-textfield-test-title-after" and @class="option"]');
 
-    $elements = $this->xpath('//label[@for="edit-form-textfield-test-title-no-show"]');
-    $this->assertFalse(isset($elements[0]), 'No label tag when title set not to display.');
+    // Verify that no label tag exists when title set not to display.
+    $this->assertSession()->elementNotExists('xpath', '//label[@for="edit-form-textfield-test-title-no-show"]');
 
     // Verify that field class is form-no-label when there is no label.
     $this->assertSession()->elementExists('xpath', '//div[contains(@class, "js-form-item-form-textfield-test-title-invisible") and contains(@class, "form-no-label")]');
diff --git a/web/core/modules/system/tests/src/Functional/Render/HtmlResponseAttachmentsTest.php b/web/core/modules/system/tests/src/Functional/Render/HtmlResponseAttachmentsTest.php
index a0ace372db..f07424b455 100644
--- a/web/core/modules/system/tests/src/Functional/Render/HtmlResponseAttachmentsTest.php
+++ b/web/core/modules/system/tests/src/Functional/Render/HtmlResponseAttachmentsTest.php
@@ -98,10 +98,9 @@ public function testRenderCachedBlock() {
    * Helper function to make assertions about added HTTP headers.
    */
   protected function assertTeapotHeaders() {
-    $headers = $this->getSession()->getResponseHeaders();
-    $this->assertEquals($headers['X-Test-Teapot'], ['Teapot Mode Active']);
-    $this->assertEquals($headers['X-Test-Teapot-Replace'], ['Teapot replaced']);
-    $this->assertEquals($headers['X-Test-Teapot-No-Replace'], ['This value is not replaced', 'This one is added']);
+    $this->assertSession()->responseHeaderEquals('X-Test-Teapot', 'Teapot Mode Active');
+    $this->assertSession()->responseHeaderEquals('X-Test-Teapot-Replace', 'Teapot replaced');
+    $this->assertSession()->responseHeaderEquals('X-Test-Teapot-No-Replace', 'This value is not replaced');
   }
 
   /**
diff --git a/web/core/modules/system/tests/src/Functional/Theme/ThemeUiTest.php b/web/core/modules/system/tests/src/Functional/Theme/ThemeUiTest.php
index fc9ede5410..daca1401a0 100644
--- a/web/core/modules/system/tests/src/Functional/Theme/ThemeUiTest.php
+++ b/web/core/modules/system/tests/src/Functional/Theme/ThemeUiTest.php
@@ -289,7 +289,7 @@ public function providerTestThemeInstallWithModuleDependencies() {
   protected function assertUninstallableTheme(array $expected_requires_list_items, $theme_name) {
     $theme_container = $this->getSession()->getPage()->find('css', "h3:contains(\"$theme_name\")")->getParent();
     $requires_list_items = $theme_container->findAll('css', '.theme-info__requires li');
-    $this->assertCount(count($expected_requires_list_items), $requires_list_items);
+    $this->assertSameSize($expected_requires_list_items, $requires_list_items);
 
     foreach ($requires_list_items as $key => $item) {
       $this->assertContains($item->getText(), $expected_requires_list_items);
diff --git a/web/core/modules/system/tests/src/Functional/UpdateSystem/UpdatePathTestBaseFilledTest.php b/web/core/modules/system/tests/src/Functional/UpdateSystem/UpdatePathTestBaseFilledTest.php
index 0b25e78bfc..56fbfc7d38 100644
--- a/web/core/modules/system/tests/src/Functional/UpdateSystem/UpdatePathTestBaseFilledTest.php
+++ b/web/core/modules/system/tests/src/Functional/UpdateSystem/UpdatePathTestBaseFilledTest.php
@@ -313,7 +313,7 @@ public function testUpdatedSite() {
     $this->drupalGet('admin/config/system/actions');
     $this->assertSession()->pageTextContains('Test action');
     $this->drupalGet('admin/config/system/actions/configure/test_action');
-    $this->assertSession()->pageTextContains('test_action');
+    $this->assertSession()->fieldValueEquals('id', 'test_action');
     $this->assertRaw('drupal.org');
 
     // Make sure our ban still exists.
diff --git a/web/core/modules/system/tests/src/Kernel/Entity/EntityReferenceSelectionReferenceableTest.php b/web/core/modules/system/tests/src/Kernel/Entity/EntityReferenceSelectionReferenceableTest.php
index a4bea10bdf..000eec20f5 100644
--- a/web/core/modules/system/tests/src/Kernel/Entity/EntityReferenceSelectionReferenceableTest.php
+++ b/web/core/modules/system/tests/src/Kernel/Entity/EntityReferenceSelectionReferenceableTest.php
@@ -186,15 +186,15 @@ public function providerTestCases() {
       // 'xyabz_', 'foo_', 'bar_', 'baz_', 'șz_', NULL, '<strong>').
       //
       // Note: Even we set the name as NULL, when retrieving the label from the
-      //   entity we'll get an empty string, meaning that this match operator
-      //   will return TRUE every time.
+      // entity we'll get an empty string, meaning that this match operator
+      // will return TRUE every time.
       [NULL, 'IS NOT NULL', 0, 9, static::$labels, 9],
       // Referenceables null, no limit. Expecting 9 items ('abc', 'Xyz_',
       // 'xyabz_', 'foo_', 'bar_', 'baz_', 'șz_', NULL, '<strong>').
       //
       // Note: Even we set the name as NULL, when retrieving the label from the
-      //   entity we'll get an empty string, meaning that this match operator
-      //   will return FALSE every time.
+      // entity we'll get an empty string, meaning that this match operator
+      // will return FALSE every time.
       [NULL, 'IS NULL', 0, 9, static::$labels, 9],
       // Referenceables containing '<strong>' markup, no limit. Expecting 1 item
       // ('<strong>').
diff --git a/web/core/modules/system/tests/src/Kernel/Extension/ModuleHandlerTest.php b/web/core/modules/system/tests/src/Kernel/Extension/ModuleHandlerTest.php
index 64956dec9e..d3411dd881 100644
--- a/web/core/modules/system/tests/src/Kernel/Extension/ModuleHandlerTest.php
+++ b/web/core/modules/system/tests/src/Kernel/Extension/ModuleHandlerTest.php
@@ -179,7 +179,7 @@ public function testUninstallProfileDependency() {
     $result = $this->moduleInstaller()->uninstall([$non_dependency]);
     $this->assertTrue($result, 'ModuleInstaller::uninstall() returns TRUE.');
     $this->assertFalse($this->moduleHandler()->moduleExists($non_dependency));
-    $this->assertEquals(drupal_get_installed_schema_version($non_dependency), SCHEMA_UNINSTALLED, "$non_dependency module was uninstalled.");
+    $this->assertEquals(SCHEMA_UNINSTALLED, drupal_get_installed_schema_version($non_dependency), "$non_dependency module was uninstalled.");
 
     // Verify that the installation profile itself was not uninstalled.
     $uninstalled_modules = \Drupal::state()->get('module_test.uninstall_order', []);
diff --git a/web/core/modules/system/tests/src/Kernel/Installer/UninstallKernelTest.php b/web/core/modules/system/tests/src/Kernel/Installer/UninstallKernelTest.php
index 12f050c8d4..81b1556113 100644
--- a/web/core/modules/system/tests/src/Kernel/Installer/UninstallKernelTest.php
+++ b/web/core/modules/system/tests/src/Kernel/Installer/UninstallKernelTest.php
@@ -3,6 +3,7 @@
 namespace Drupal\Tests\system\Kernel\Installer;
 
 use Drupal\KernelTests\KernelTestBase;
+use Drupal\module_test\PluginManagerCacheClearer;
 
 /**
  * Tests the uninstallation of modules.
@@ -48,4 +49,24 @@ public function testUninstallMedia() {
     \Drupal::service('module_installer')->uninstall(['file']);
   }
 
+  /**
+   * Tests uninstalling a module with a plugin cache clearer service.
+   */
+  public function testUninstallPluginCacheClear() {
+    \Drupal::service('module_installer')->install(['module_test']);
+    $this->assertFalse($this->container->get('state')->get(PluginManagerCacheClearer::class));
+    \Drupal::service('module_installer')->install(['dblog']);
+    $this->assertTrue($this->container->get('state')->get(PluginManagerCacheClearer::class));
+
+    // The plugin cache clearer service should be called during dblog uninstall
+    // without the dependency.
+    \Drupal::service('module_installer')->uninstall(['dblog']);
+    $this->assertFalse($this->container->get('state')->get(PluginManagerCacheClearer::class));
+
+    // The service should not be called during module_test uninstall.
+    $this->container->get('state')->delete(PluginManagerCacheClearer::class);
+    \Drupal::service('module_installer')->uninstall(['module_test']);
+    $this->assertNull($this->container->get('state')->get(PluginManagerCacheClearer::class));
+  }
+
 }
diff --git a/web/core/modules/system/tests/src/Kernel/Scripts/DbCommandBaseTest.php b/web/core/modules/system/tests/src/Kernel/Scripts/DbCommandBaseTest.php
index 3c6d8aa34e..cef2414ec0 100644
--- a/web/core/modules/system/tests/src/Kernel/Scripts/DbCommandBaseTest.php
+++ b/web/core/modules/system/tests/src/Kernel/Scripts/DbCommandBaseTest.php
@@ -96,10 +96,12 @@ public function testPrefix() {
     $this->assertEquals('extra2', $command->getDatabaseConnection($command_tester->getInput())->tablePrefix());
 
     // This breaks simpletest cleanup.
+    // @code
     //    $command_tester->execute([
     //      '--prefix' => 'notsimpletest',
     //    ]);
     //    $this->assertEquals('notsimpletest', $command->getDatabaseConnection($command_tester->getInput())->tablePrefix());
+    // @endcode
   }
 
 }
diff --git a/web/core/modules/taxonomy/src/Plugin/migrate/source/d6/Term.php b/web/core/modules/taxonomy/src/Plugin/migrate/source/d6/Term.php
index da048af4df..f9ec2a7037 100644
--- a/web/core/modules/taxonomy/src/Plugin/migrate/source/d6/Term.php
+++ b/web/core/modules/taxonomy/src/Plugin/migrate/source/d6/Term.php
@@ -6,7 +6,7 @@
 use Drupal\migrate_drupal\Plugin\migrate\source\DrupalSqlBase;
 
 /**
- * Taxonomy term source from database.
+ * Drupal 6 taxonomy term source from database.
  *
  * Available configuration keys:
  * - bundle: (optional) The taxonomy vocabulary (vid) to filter terms retrieved
@@ -33,7 +33,8 @@
  * In this example terms of vocabularies with 'vid' one of 1, 3, 5 are retrieved
  * from the source database.
  *
- * For additional configuration keys, refer to the parent classes:
+ * For additional configuration keys, refer to the parent classes.
+ *
  * @see \Drupal\migrate\Plugin\migrate\source\SqlBase
  * @see \Drupal\migrate\Plugin\migrate\source\SourcePluginBase
  *
diff --git a/web/core/modules/taxonomy/src/Plugin/migrate/source/d6/TermLocalizedTranslation.php b/web/core/modules/taxonomy/src/Plugin/migrate/source/d6/TermLocalizedTranslation.php
index ce44978b76..6fd6a1ce4e 100644
--- a/web/core/modules/taxonomy/src/Plugin/migrate/source/d6/TermLocalizedTranslation.php
+++ b/web/core/modules/taxonomy/src/Plugin/migrate/source/d6/TermLocalizedTranslation.php
@@ -5,9 +5,10 @@
 use Drupal\migrate\Row;
 
 /**
- * Gets i18n taxonomy terms from source database.
+ * Drupal 6 i18n taxonomy terms from source database.
+ *
+ * For available configuration keys, refer to the parent classes.
  *
- * For available configuration keys, refer to the parent classes:
  * @see \Drupal\taxonomy\Plugin\migrate\source\d6\Term
  * @see \Drupal\migrate\Plugin\migrate\source\SqlBase
  * @see \Drupal\migrate\Plugin\migrate\source\SourcePluginBase
diff --git a/web/core/modules/taxonomy/src/Plugin/migrate/source/d6/TermNode.php b/web/core/modules/taxonomy/src/Plugin/migrate/source/d6/TermNode.php
index a4ad66f7d9..85be2501c1 100644
--- a/web/core/modules/taxonomy/src/Plugin/migrate/source/d6/TermNode.php
+++ b/web/core/modules/taxonomy/src/Plugin/migrate/source/d6/TermNode.php
@@ -6,7 +6,29 @@
 use Drupal\migrate_drupal\Plugin\migrate\source\DrupalSqlBase;
 
 /**
- * Source returning tids from the term_node table for the current revision.
+ * Drupal 6 term/node relationships (current revision) source from database.
+ *
+ * Available configuration keys:
+ * - vid: (optional) The taxonomy vocabulary (vid) to filter terms retrieved
+ *   from the source - should be an integer. If omitted, all terms are
+ *   retrieved.
+ *
+ * Example:
+ *
+ * @code
+ * source:
+ *   plugin: d6_term_node
+ *   vid: 7
+ * @endcode
+ *
+ * In this example the relations between nodes and terms are retrieved from
+ * the source database. Source rows include only terms that belong to the
+ * vocabulary with 'vid' equal to 7.
+ *
+ * For additional configuration keys, refer to the parent classes.
+ *
+ * @see \Drupal\migrate\Plugin\migrate\source\SqlBase
+ * @see \Drupal\migrate\Plugin\migrate\source\SourcePluginBase
  *
  * @MigrateSource(
  *   id = "d6_term_node",
diff --git a/web/core/modules/taxonomy/src/Plugin/migrate/source/d6/TermNodeRevision.php b/web/core/modules/taxonomy/src/Plugin/migrate/source/d6/TermNodeRevision.php
index 96d30d48af..600f963bd5 100644
--- a/web/core/modules/taxonomy/src/Plugin/migrate/source/d6/TermNodeRevision.php
+++ b/web/core/modules/taxonomy/src/Plugin/migrate/source/d6/TermNodeRevision.php
@@ -3,7 +3,13 @@
 namespace Drupal\taxonomy\Plugin\migrate\source\d6;
 
 /**
- * Source returning tids from the term_node table for the non-current revision.
+ * Drupal 6 term/node relationships (non-current revision) source from database.
+ *
+ * For available configuration keys, refer to the parent classes.
+ *
+ * @see \Drupal\taxonomy\Plugin\migrate\source\d6\TermNode
+ * @see \Drupal\migrate\Plugin\migrate\source\SqlBase
+ * @see \Drupal\migrate\Plugin\migrate\source\SourcePluginBase
  *
  * @MigrateSource(
  *   id = "d6_term_node_revision",
diff --git a/web/core/modules/taxonomy/src/Plugin/migrate/source/d6/Vocabulary.php b/web/core/modules/taxonomy/src/Plugin/migrate/source/d6/Vocabulary.php
index 767daf45e1..9a3e68860e 100644
--- a/web/core/modules/taxonomy/src/Plugin/migrate/source/d6/Vocabulary.php
+++ b/web/core/modules/taxonomy/src/Plugin/migrate/source/d6/Vocabulary.php
@@ -9,6 +9,11 @@
 /**
  * Drupal 6 vocabularies source from database.
  *
+ * For available configuration keys, refer to the parent classes.
+ *
+ * @see \Drupal\migrate\Plugin\migrate\source\SqlBase
+ * @see \Drupal\migrate\Plugin\migrate\source\SourcePluginBase
+ *
  * @MigrateSource(
  *   id = "d6_taxonomy_vocabulary",
  *   source_module = "taxonomy"
diff --git a/web/core/modules/taxonomy/src/Plugin/migrate/source/d6/VocabularyPerType.php b/web/core/modules/taxonomy/src/Plugin/migrate/source/d6/VocabularyPerType.php
index 16a57d86f6..c76b0bb239 100644
--- a/web/core/modules/taxonomy/src/Plugin/migrate/source/d6/VocabularyPerType.php
+++ b/web/core/modules/taxonomy/src/Plugin/migrate/source/d6/VocabularyPerType.php
@@ -5,7 +5,12 @@
 use Drupal\migrate\Row;
 
 /**
- * Gets all the vocabularies based on the node types that have Taxonomy enabled.
+ * Drupal 6 vocabularies with associated node types source from database.
+ *
+ * For available configuration keys, refer to the parent classes.
+ *
+ * @see \Drupal\migrate\Plugin\migrate\source\SqlBase
+ * @see \Drupal\migrate\Plugin\migrate\source\SourcePluginBase
  *
  * @MigrateSource(
  *   id = "d6_taxonomy_vocabulary_per_type",
diff --git a/web/core/modules/taxonomy/src/Plugin/migrate/source/d6/VocabularyTranslation.php b/web/core/modules/taxonomy/src/Plugin/migrate/source/d6/VocabularyTranslation.php
index 6c4c1120c8..294da00e31 100644
--- a/web/core/modules/taxonomy/src/Plugin/migrate/source/d6/VocabularyTranslation.php
+++ b/web/core/modules/taxonomy/src/Plugin/migrate/source/d6/VocabularyTranslation.php
@@ -6,7 +6,12 @@
 use Drupal\migrate_drupal\Plugin\migrate\source\DrupalSqlBase;
 
 /**
- * Drupal 6 vocabulary translations from source database.
+ * Drupal 6 i18n vocabulary translations from source database.
+ *
+ * For available configuration keys, refer to the parent classes.
+ *
+ * @see \Drupal\migrate\Plugin\migrate\source\SqlBase
+ * @see \Drupal\migrate\Plugin\migrate\source\SourcePluginBase
  *
  * @MigrateSource(
  *   id = "d6_taxonomy_vocabulary_translation",
diff --git a/web/core/modules/taxonomy/src/Plugin/migrate/source/d7/Term.php b/web/core/modules/taxonomy/src/Plugin/migrate/source/d7/Term.php
index 2ba29e4ae2..40c7a6bcb9 100644
--- a/web/core/modules/taxonomy/src/Plugin/migrate/source/d7/Term.php
+++ b/web/core/modules/taxonomy/src/Plugin/migrate/source/d7/Term.php
@@ -6,7 +6,7 @@
 use Drupal\migrate_drupal\Plugin\migrate\source\d7\FieldableEntity;
 
 /**
- * Taxonomy term source from database.
+ * Drupal 7 taxonomy term source from database.
  *
  * Available configuration keys:
  * - bundle: (optional) The taxonomy vocabulary (machine name) to filter terms
@@ -33,7 +33,8 @@
  * In this example terms of 'tags' and 'forums' vocabularies are retrieved
  * from the source database.
  *
- * For additional configuration keys, refer to the parent classes:
+ * For additional configuration keys, refer to the parent classes.
+ *
  * @see \Drupal\migrate\Plugin\migrate\source\SqlBase
  * @see \Drupal\migrate\Plugin\migrate\source\SourcePluginBase
  *
diff --git a/web/core/modules/taxonomy/src/Plugin/migrate/source/d7/TermEntityTranslation.php b/web/core/modules/taxonomy/src/Plugin/migrate/source/d7/TermEntityTranslation.php
index cd0f1c4a34..594cde8fe9 100644
--- a/web/core/modules/taxonomy/src/Plugin/migrate/source/d7/TermEntityTranslation.php
+++ b/web/core/modules/taxonomy/src/Plugin/migrate/source/d7/TermEntityTranslation.php
@@ -6,7 +6,7 @@
 use Drupal\migrate_drupal\Plugin\migrate\source\d7\FieldableEntity;
 
 /**
- * Provides Drupal 7 taxonomy term entity translation source plugin.
+ * Drupal 7 taxonomy term entity translation source plugin.
  *
  * Available configuration keys:
  * - bundle: (optional) The taxonomy vocabulary (machine name) to filter terms
@@ -33,7 +33,8 @@
  * In this example terms of 'tags' and 'forums' vocabularies are retrieved
  * from the source database.
  *
- * For additional configuration keys, refer to the parent classes:
+ * For additional configuration keys, refer to the parent classes.
+ *
  * @see \Drupal\migrate\Plugin\migrate\source\SqlBase
  * @see \Drupal\migrate\Plugin\migrate\source\SourcePluginBase
  *
diff --git a/web/core/modules/taxonomy/src/Plugin/migrate/source/d7/TermLocalizedTranslation.php b/web/core/modules/taxonomy/src/Plugin/migrate/source/d7/TermLocalizedTranslation.php
index a366f2fe94..a06ec0d138 100644
--- a/web/core/modules/taxonomy/src/Plugin/migrate/source/d7/TermLocalizedTranslation.php
+++ b/web/core/modules/taxonomy/src/Plugin/migrate/source/d7/TermLocalizedTranslation.php
@@ -6,9 +6,10 @@
 use Drupal\migrate\Row;
 
 /**
- * Gets i18n taxonomy terms from source database.
+ * Drupal 7 i18n taxonomy terms from source database.
+ *
+ * For available configuration keys, refer to the parent classes.
  *
- * For available configuration keys, refer to the parent classes:
  * @see \Drupal\taxonomy\Plugin\migrate\source\d7\Term
  * @see \Drupal\migrate\Plugin\migrate\source\SqlBase
  * @see \Drupal\migrate\Plugin\migrate\source\SourcePluginBase
diff --git a/web/core/modules/taxonomy/src/Plugin/migrate/source/d7/TermTranslation.php b/web/core/modules/taxonomy/src/Plugin/migrate/source/d7/TermTranslation.php
index 4357a3122f..50fb58161a 100644
--- a/web/core/modules/taxonomy/src/Plugin/migrate/source/d7/TermTranslation.php
+++ b/web/core/modules/taxonomy/src/Plugin/migrate/source/d7/TermTranslation.php
@@ -5,9 +5,10 @@
 use Drupal\migrate\Row;
 
 /**
- * Gets i18n taxonomy terms from source database.
+ * Drupal 7 i18n taxonomy terms from source database.
+ *
+ * For available configuration keys, refer to the parent classes.
  *
- * For available configuration keys, refer to the parent classes:
  * @see \Drupal\taxonomy\Plugin\migrate\source\d7\Term
  * @see \Drupal\migrate\Plugin\migrate\source\SqlBase
  * @see \Drupal\migrate\Plugin\migrate\source\SourcePluginBase
diff --git a/web/core/modules/taxonomy/src/Plugin/migrate/source/d7/Vocabulary.php b/web/core/modules/taxonomy/src/Plugin/migrate/source/d7/Vocabulary.php
index 82048a3c2f..cf3db66cf6 100644
--- a/web/core/modules/taxonomy/src/Plugin/migrate/source/d7/Vocabulary.php
+++ b/web/core/modules/taxonomy/src/Plugin/migrate/source/d7/Vocabulary.php
@@ -8,6 +8,11 @@
 /**
  * Drupal 7 vocabularies source from database.
  *
+ * For available configuration keys, refer to the parent classes.
+ *
+ * @see \Drupal\migrate\Plugin\migrate\source\SqlBase
+ * @see \Drupal\migrate\Plugin\migrate\source\SourcePluginBase
+ *
  * @MigrateSource(
  *   id = "d7_taxonomy_vocabulary",
  *   source_module = "taxonomy"
diff --git a/web/core/modules/taxonomy/src/Plugin/migrate/source/d7/VocabularyTranslation.php b/web/core/modules/taxonomy/src/Plugin/migrate/source/d7/VocabularyTranslation.php
index 1191fdaeb9..9d6c9ce933 100644
--- a/web/core/modules/taxonomy/src/Plugin/migrate/source/d7/VocabularyTranslation.php
+++ b/web/core/modules/taxonomy/src/Plugin/migrate/source/d7/VocabularyTranslation.php
@@ -3,7 +3,12 @@
 namespace Drupal\taxonomy\Plugin\migrate\source\d7;
 
 /**
- * Drupal 7 vocabulary translations from source database.
+ * Drupal 7 i18n vocabulary translations source from database.
+ *
+ * For available configuration keys, refer to the parent classes.
+ *
+ * @see \Drupal\migrate\Plugin\migrate\source\SqlBase
+ * @see \Drupal\migrate\Plugin\migrate\source\SourcePluginBase
  *
  * @MigrateSource(
  *   id = "d7_taxonomy_vocabulary_translation",
diff --git a/web/core/modules/taxonomy/src/Plugin/views/filter/TaxonomyIndexTidDepth.php b/web/core/modules/taxonomy/src/Plugin/views/filter/TaxonomyIndexTidDepth.php
index 6b710d6234..e3372ae191 100644
--- a/web/core/modules/taxonomy/src/Plugin/views/filter/TaxonomyIndexTidDepth.php
+++ b/web/core/modules/taxonomy/src/Plugin/views/filter/TaxonomyIndexTidDepth.php
@@ -60,7 +60,7 @@ public function query() {
 
     // The normal use of ensureMyTable() here breaks Views.
     // So instead we trick the filter into using the alias of the base table.
-    //   See https://www.drupal.org/node/271833.
+    // See https://www.drupal.org/node/271833.
     // If a relationship is set, we must use the alias it provides.
     if (!empty($this->relationship)) {
       $this->tableAlias = $this->relationship;
diff --git a/web/core/modules/tour/tests/src/Functional/TourTest.php b/web/core/modules/tour/tests/src/Functional/TourTest.php
index 329f3284cb..c15d00f957 100644
--- a/web/core/modules/tour/tests/src/Functional/TourTest.php
+++ b/web/core/modules/tour/tests/src/Functional/TourTest.php
@@ -207,7 +207,7 @@ public function testTourFunctionality() {
     $this->assertCount(1, $elements, 'Found code tip was weighted last and had "End tour".');
 
     // Test hook_tour_alter().
-    $this->assertSession()->pageTextContains('Altered by hook_tour_tips_alter');
+    $this->assertSession()->responseContains('Altered by hook_tour_tips_alter');
 
     // Navigate to tour-test-3 and verify the tour_test_1 tip is found with
     // appropriate classes.
diff --git a/web/core/modules/tracker/src/Plugin/migrate/source/d7/TrackerNode.php b/web/core/modules/tracker/src/Plugin/migrate/source/d7/TrackerNode.php
index 2805b7d754..4713aa80f0 100644
--- a/web/core/modules/tracker/src/Plugin/migrate/source/d7/TrackerNode.php
+++ b/web/core/modules/tracker/src/Plugin/migrate/source/d7/TrackerNode.php
@@ -7,6 +7,11 @@
 /**
  * Drupal 7 tracker node source from database.
  *
+ * For available configuration keys, refer to the parent classes.
+ *
+ * @see \Drupal\migrate\Plugin\migrate\source\SqlBase
+ * @see \Drupal\migrate\Plugin\migrate\source\SourcePluginBase
+ *
  * @MigrateSource(
  *   id = "d7_tracker_node",
  *   source_module = "tracker"
diff --git a/web/core/modules/tracker/src/Plugin/migrate/source/d7/TrackerUser.php b/web/core/modules/tracker/src/Plugin/migrate/source/d7/TrackerUser.php
index 4991dbe221..c566592aed 100644
--- a/web/core/modules/tracker/src/Plugin/migrate/source/d7/TrackerUser.php
+++ b/web/core/modules/tracker/src/Plugin/migrate/source/d7/TrackerUser.php
@@ -7,6 +7,11 @@
 /**
  * Drupal 7 tracker user source from database.
  *
+ * For available configuration keys, refer to the parent classes.
+ *
+ * @see \Drupal\migrate\Plugin\migrate\source\SqlBase
+ * @see \Drupal\migrate\Plugin\migrate\source\SourcePluginBase
+ *
  * @MigrateSource(
  *   id = "d7_tracker_user",
  *   source_module = "tracker"
diff --git a/web/core/modules/update/src/Plugin/migrate/source/UpdateSettings.php b/web/core/modules/update/src/Plugin/migrate/source/UpdateSettings.php
index 4001338476..69a9be8397 100644
--- a/web/core/modules/update/src/Plugin/migrate/source/UpdateSettings.php
+++ b/web/core/modules/update/src/Plugin/migrate/source/UpdateSettings.php
@@ -5,7 +5,13 @@
 use Drupal\migrate_drupal\Plugin\migrate\source\Variable;
 
 /**
- * Update settings source plugin.
+ * Drupal 6/7 Update settings source from database.
+ *
+ * For available configuration keys, refer to the parent classes.
+ *
+ * @see \Drupal\migrate_drupal\Plugin\migrate\source\Variable
+ * @see \Drupal\migrate\Plugin\migrate\source\SqlBase
+ * @see \Drupal\migrate\Plugin\migrate\source\SourcePluginBase
  *
  * @MigrateSource(
  *   id = "update_settings",
diff --git a/web/core/modules/update/src/UpdateProcessor.php b/web/core/modules/update/src/UpdateProcessor.php
index 1e2cfb7432..932a0b5d09 100644
--- a/web/core/modules/update/src/UpdateProcessor.php
+++ b/web/core/modules/update/src/UpdateProcessor.php
@@ -166,7 +166,7 @@ public function processFetchTask($project) {
     }
     if (!empty($data)) {
       $available = $this->parseXml($data);
-      // @todo: Purge release data we don't need. See
+      // @todo Purge release data we don't need. See
       //   https://www.drupal.org/node/238950.
       if (!empty($available)) {
         // Only if we fetched and parsed something sane do we return success.
diff --git a/web/core/modules/update/tests/fixtures/release-history/bbb_update_test.1_0.xml b/web/core/modules/update/tests/fixtures/release-history/bbb_update_test.1_0.xml
index c93b5a2b80..5625c491ae 100644
--- a/web/core/modules/update/tests/fixtures/release-history/bbb_update_test.1_0.xml
+++ b/web/core/modules/update/tests/fixtures/release-history/bbb_update_test.1_0.xml
@@ -14,7 +14,7 @@
   <name>bbb_update_test 8.x-1.0</name>
   <version>8.x-1.0</version>
   <status>published</status>
-  <release_link>http://example.com/bbb_update_test-7-x-1-0-release</release_link>
+  <release_link>http://example.com/bbb_update_test-8-x-1-0-release</release_link>
   <download_link>http://example.com/bbb_update_test-8.x-1.0.tar.gz</download_link>
   <date>1250424521</date>
   <terms>
diff --git a/web/core/modules/update/tests/fixtures/release-history/ccc_update_test.1_0.xml b/web/core/modules/update/tests/fixtures/release-history/ccc_update_test.1_0.xml
index 5c172fe4c1..df851d202d 100644
--- a/web/core/modules/update/tests/fixtures/release-history/ccc_update_test.1_0.xml
+++ b/web/core/modules/update/tests/fixtures/release-history/ccc_update_test.1_0.xml
@@ -14,7 +14,7 @@
   <name>ccc_update_test 8.x-1.0</name>
   <version>8.x-1.0</version>
   <status>published</status>
-  <release_link>http://example.com/ccc_update_test-7-x-1-0-release</release_link>
+  <release_link>http://example.com/ccc_update_test-8-x-1-0-release</release_link>
   <download_link>http://example.com/ccc_update_test-8.x-1.0.tar.gz</download_link>
   <date>1250424521</date>
   <terms>
diff --git a/web/core/modules/update/tests/fixtures/release-history/update_test_basetheme.1_1-sec.xml b/web/core/modules/update/tests/fixtures/release-history/update_test_basetheme.1_1-sec.xml
index 143f393569..96fc287fcc 100644
--- a/web/core/modules/update/tests/fixtures/release-history/update_test_basetheme.1_1-sec.xml
+++ b/web/core/modules/update/tests/fixtures/release-history/update_test_basetheme.1_1-sec.xml
@@ -14,7 +14,7 @@
   <name>update_test_basetheme 8.x-1.1</name>
   <version>8.x-1.1</version>
   <status>published</status>
-  <release_link>http://example.com/update_test_basetheme-7-x-1-1-release</release_link>
+  <release_link>http://example.com/update_test_basetheme-8-x-1-1-release</release_link>
   <download_link>http://example.com/update_test_basetheme-8.x-1.1.tar.gz</download_link>
   <date>1250624521</date>
   <terms>
@@ -27,7 +27,7 @@
   <name>update_test_basetheme 8.x-1.0</name>
   <version>8.x-1.0</version>
   <status>published</status>
-  <release_link>http://example.com/update_test_basetheme-7-x-1-0-release</release_link>
+  <release_link>http://example.com/update_test_basetheme-8-x-1-0-release</release_link>
   <download_link>http://example.com/update_test_basetheme-8.x-1.0.tar.gz</download_link>
   <date>1250524521</date>
   <terms>
diff --git a/web/core/modules/update/tests/fixtures/release-history/update_test_subtheme.1_0.xml b/web/core/modules/update/tests/fixtures/release-history/update_test_subtheme.1_0.xml
index 946f5dc6d9..2c3b01a91a 100644
--- a/web/core/modules/update/tests/fixtures/release-history/update_test_subtheme.1_0.xml
+++ b/web/core/modules/update/tests/fixtures/release-history/update_test_subtheme.1_0.xml
@@ -14,7 +14,7 @@
   <name>update_test_subtheme 8.x-1.0</name>
   <version>8.x-1.0</version>
   <status>published</status>
-  <release_link>http://example.com/update_test_subtheme-7-x-1-0-release</release_link>
+  <release_link>http://example.com/update_test_subtheme-8-x-1-0-release</release_link>
   <download_link>http://example.com/update_test_subtheme-8.x-1.0.tar.gz</download_link>
   <date>1250524521</date>
   <terms>
diff --git a/web/core/modules/update/tests/src/Functional/UpdateContribTest.php b/web/core/modules/update/tests/src/Functional/UpdateContribTest.php
index 0d24aa22a6..2eb4e0dae8 100644
--- a/web/core/modules/update/tests/src/Functional/UpdateContribTest.php
+++ b/web/core/modules/update/tests/src/Functional/UpdateContribTest.php
@@ -211,7 +211,7 @@ public function testUpdateContribOrder() {
    */
   public function testUpdateBaseThemeSecurityUpdate() {
     // @todo https://www.drupal.org/node/2338175 base themes have to be
-    //  installed.
+    //   installed.
     // Only install the subtheme, not the base theme.
     \Drupal::service('theme_installer')->install(['update_test_subtheme']);
 
@@ -242,7 +242,8 @@ public function testUpdateBaseThemeSecurityUpdate() {
     ];
     $this->refreshUpdateStatus($xml_mapping);
     $this->assertSession()->pageTextContains('Security update required!');
-    $this->assertRaw(Link::fromTextAndUrl(t('Update test base theme'), Url::fromUri('http://example.com/project/update_test_basetheme'))->toString());
+    $this->updateProject = 'update_test_basetheme';
+    $this->assertVersionUpdateLinks('Security update', '8.x-1.1');
   }
 
   /**
@@ -872,8 +873,8 @@ protected function assertCoreCompatibilityMessage($version, $expected_range, $ex
       $this->assertFalse($compatibility_details->hasAttribute('open'));
       $this->assertSame('Compatible', $details_summary_element->getText());
       $this->assertEquals(
-        $update_element->findLink('Download')->getAttribute('href'),
-        "http://example.com/{$this->updateProject}-$download_version.tar.gz"
+        "http://example.com/{$this->updateProject}-$download_version.tar.gz",
+        $update_element->findLink('Download')->getAttribute('href')
       );
     }
     else {
diff --git a/web/core/modules/user/src/AccountForm.php b/web/core/modules/user/src/AccountForm.php
index 0a78611f24..2358d9b654 100644
--- a/web/core/modules/user/src/AccountForm.php
+++ b/web/core/modules/user/src/AccountForm.php
@@ -75,9 +75,9 @@ public function form(array $form, FormStateInterface $form_state) {
 
     // For a new account, there are 2 sub-cases:
     // $self_register: A user creates their own, new, account
-    //   (path '/user/register')
+    // (path '/user/register')
     // $admin_create: An administrator creates a new account for another user
-    //   (path '/admin/people/create')
+    // (path '/admin/people/create')
     // If the current user is logged in and has permission to create users
     // then it must be the second case.
     $admin_create = $register && $account->access('create');
@@ -352,7 +352,7 @@ public function syncUserLangcode($entity_type_id, UserInterface $user, array &$f
    */
   public function buildEntity(array $form, FormStateInterface $form_state) {
     // Change the roles array to a list of enabled roles.
-    // @todo: Alter the form state as the form values are directly extracted and
+    // @todo Alter the form state as the form values are directly extracted and
     //   set on the field, which throws an exception as the list requires
     //   numeric keys. Allow to override this per field. As this function is
     //   called twice, we have to prevent it from getting the array keys twice.
diff --git a/web/core/modules/user/tests/src/Functional/RestRegisterUserTest.php b/web/core/modules/user/tests/src/Functional/RestRegisterUserTest.php
index f3f269a739..7bcdf26583 100644
--- a/web/core/modules/user/tests/src/Functional/RestRegisterUserTest.php
+++ b/web/core/modules/user/tests/src/Functional/RestRegisterUserTest.php
@@ -84,7 +84,7 @@ public function testRegisterUser() {
     $this->assertFalse(empty($user->getPassword()));
     $email_count = count($this->drupalGetMails());
 
-    $this->assertEquals($email_count, 0);
+    $this->assertEquals(0, $email_count);
 
     // Attempt to register without sending a password.
     $response = $this->registerRequest('Rick.Deckard', FALSE);
diff --git a/web/core/modules/user/tests/src/Kernel/Plugin/migrate/source/ProfileFieldTest.php b/web/core/modules/user/tests/src/Kernel/Plugin/migrate/source/ProfileFieldTest.php
index c24a0a79e2..1f29505a5a 100644
--- a/web/core/modules/user/tests/src/Kernel/Plugin/migrate/source/ProfileFieldTest.php
+++ b/web/core/modules/user/tests/src/Kernel/Plugin/migrate/source/ProfileFieldTest.php
@@ -103,8 +103,8 @@ public function providerSource() {
     ];
 
     // Expected options are:
-    //  for "checkbox" fields - array with NULL options
-    //  for "selection" fields - options in both keys and values
+    // - for "checkbox" fields - array with NULL options.
+    // - for "selection" fields - options in both keys and values.
     $expected_field_options = [
       '',
       '',
diff --git a/web/core/modules/user/tests/src/Kernel/UserMailNotifyTest.php b/web/core/modules/user/tests/src/Kernel/UserMailNotifyTest.php
index 3ef3546f22..8a07f4a290 100644
--- a/web/core/modules/user/tests/src/Kernel/UserMailNotifyTest.php
+++ b/web/core/modules/user/tests/src/Kernel/UserMailNotifyTest.php
@@ -88,7 +88,7 @@ public function testUserMailsSent($op, array $mail_keys) {
       $filter = ['key' => $key];
       $this->assertNotEmpty($this->getMails($filter));
     }
-    $this->assertCount(count($mail_keys), $this->getMails());
+    $this->assertSameSize($mail_keys, $this->getMails());
   }
 
   /**
diff --git a/web/core/modules/user/tests/src/Kernel/UserRoleEntityTest.php b/web/core/modules/user/tests/src/Kernel/UserRoleEntityTest.php
index b597c3ddae..89f272297f 100644
--- a/web/core/modules/user/tests/src/Kernel/UserRoleEntityTest.php
+++ b/web/core/modules/user/tests/src/Kernel/UserRoleEntityTest.php
@@ -18,13 +18,13 @@ public function testOrderOfPermissions() {
       ->grantPermission('a')
       ->grantPermission('c')
       ->save();
-    $this->assertEquals($role->getPermissions(), ['a', 'b', 'c']);
+    $this->assertEquals(['a', 'b', 'c'], $role->getPermissions());
 
     $role->revokePermission('b')->save();
-    $this->assertEquals($role->getPermissions(), ['a', 'c']);
+    $this->assertEquals(['a', 'c'], $role->getPermissions());
 
     $role->grantPermission('b')->save();
-    $this->assertEquals($role->getPermissions(), ['a', 'b', 'c']);
+    $this->assertEquals(['a', 'b', 'c'], $role->getPermissions());
   }
 
 }
diff --git a/web/core/modules/user/tests/src/Unit/PermissionHandlerTest.php b/web/core/modules/user/tests/src/Unit/PermissionHandlerTest.php
index 92b259ea5c..6a45251033 100644
--- a/web/core/modules/user/tests/src/Unit/PermissionHandlerTest.php
+++ b/web/core/modules/user/tests/src/Unit/PermissionHandlerTest.php
@@ -257,22 +257,14 @@ public function testBuildPermissionsYamlCallback() {
       ->method('getModuleList')
       ->willReturn(array_flip($modules));
 
-    $this->controllerResolver->expects($this->at(0))
+    $this->controllerResolver->expects($this->exactly(4))
       ->method('getControllerFromDefinition')
-      ->with('Drupal\\user\\Tests\\TestPermissionCallbacks::singleDescription')
-      ->willReturn([new TestPermissionCallbacks(), 'singleDescription']);
-    $this->controllerResolver->expects($this->at(1))
-      ->method('getControllerFromDefinition')
-      ->with('Drupal\\user\\Tests\\TestPermissionCallbacks::titleDescription')
-      ->willReturn([new TestPermissionCallbacks(), 'titleDescription']);
-    $this->controllerResolver->expects($this->at(2))
-      ->method('getControllerFromDefinition')
-      ->with('Drupal\\user\\Tests\\TestPermissionCallbacks::titleProvider')
-      ->willReturn([new TestPermissionCallbacks(), 'titleProvider']);
-    $this->controllerResolver->expects($this->at(3))
-      ->method('getControllerFromDefinition')
-      ->with('Drupal\\user\\Tests\\TestPermissionCallbacks::titleDescriptionRestrictAccess')
-      ->willReturn([new TestPermissionCallbacks(), 'titleDescriptionRestrictAccess']);
+      ->willReturnMap([
+        ['Drupal\\user\\Tests\\TestPermissionCallbacks::singleDescription', [new TestPermissionCallbacks(), 'singleDescription']],
+        ['Drupal\\user\\Tests\\TestPermissionCallbacks::titleDescription', [new TestPermissionCallbacks(), 'titleDescription']],
+        ['Drupal\\user\\Tests\\TestPermissionCallbacks::titleProvider', [new TestPermissionCallbacks(), 'titleProvider']],
+        ['Drupal\\user\\Tests\\TestPermissionCallbacks::titleDescriptionRestrictAccess', [new TestPermissionCallbacks(), 'titleDescriptionRestrictAccess']],
+      ]);
 
     $this->permissionHandler = new PermissionHandler($this->moduleHandler, $this->stringTranslation, $this->controllerResolver);
 
@@ -327,12 +319,12 @@ public function testPermissionsYamlStaticAndCallback() {
     $actual_permissions = $this->permissionHandler->getPermissions();
 
     $this->assertCount(2, $actual_permissions);
-    $this->assertEquals($actual_permissions['access module a']['title'], 'Access A');
-    $this->assertEquals($actual_permissions['access module a']['provider'], 'module_a');
-    $this->assertEquals($actual_permissions['access module a']['description'], 'bla bla');
-    $this->assertEquals($actual_permissions['access module b']['title'], 'Access B');
-    $this->assertEquals($actual_permissions['access module b']['provider'], 'module_a');
-    $this->assertEquals($actual_permissions['access module b']['description'], 'bla bla');
+    $this->assertEquals('Access A', $actual_permissions['access module a']['title']);
+    $this->assertEquals('module_a', $actual_permissions['access module a']['provider']);
+    $this->assertEquals('bla bla', $actual_permissions['access module a']['description']);
+    $this->assertEquals('Access B', $actual_permissions['access module b']['title']);
+    $this->assertEquals('module_a', $actual_permissions['access module b']['provider']);
+    $this->assertEquals('bla bla', $actual_permissions['access module b']['description']);
   }
 
   /**
@@ -343,14 +335,14 @@ public function testPermissionsYamlStaticAndCallback() {
    */
   protected function assertPermissions(array $actual_permissions) {
     $this->assertCount(4, $actual_permissions);
-    $this->assertEquals($actual_permissions['access_module_a']['title'], 'single_description');
-    $this->assertEquals($actual_permissions['access_module_a']['provider'], 'module_a');
-    $this->assertEquals($actual_permissions['access module b']['title'], 'Access B');
-    $this->assertEquals($actual_permissions['access module b']['provider'], 'module_b');
-    $this->assertEquals($actual_permissions['access_module_c']['title'], 'Access C');
-    $this->assertEquals($actual_permissions['access_module_c']['provider'], 'module_c');
-    $this->assertEquals($actual_permissions['access_module_c']['restrict access'], TRUE);
-    $this->assertEquals($actual_permissions['access module a via module b']['provider'], 'module_a');
+    $this->assertEquals('single_description', $actual_permissions['access_module_a']['title']);
+    $this->assertEquals('module_a', $actual_permissions['access_module_a']['provider']);
+    $this->assertEquals('Access B', $actual_permissions['access module b']['title']);
+    $this->assertEquals('module_b', $actual_permissions['access module b']['provider']);
+    $this->assertEquals('Access C', $actual_permissions['access_module_c']['title']);
+    $this->assertEquals('module_c', $actual_permissions['access_module_c']['provider']);
+    $this->assertTrue($actual_permissions['access_module_c']['restrict access']);
+    $this->assertEquals('module_a', $actual_permissions['access module a via module b']['provider']);
   }
 
 }
diff --git a/web/core/modules/views/src/Form/ViewsExposedForm.php b/web/core/modules/views/src/Form/ViewsExposedForm.php
index 87d4559413..bbeb4db276 100644
--- a/web/core/modules/views/src/Form/ViewsExposedForm.php
+++ b/web/core/modules/views/src/Form/ViewsExposedForm.php
@@ -208,7 +208,7 @@ public function submitForm(array &$form, FormStateInterface $form_state) {
       if (!empty($key) && !in_array($key, $exclude)) {
         if (is_array($value)) {
           // Handle checkboxes, we only want to include the checked options.
-          // @todo: revisit the need for this when
+          // @todo revisit the need for this when
           //   https://www.drupal.org/node/342316 is resolved.
           $checked = Checkboxes::getCheckedCheckboxes($value);
           foreach ($checked as $option_id) {
diff --git a/web/core/modules/views/src/Plugin/views/cache/CachePluginBase.php b/web/core/modules/views/src/Plugin/views/cache/CachePluginBase.php
index fd9278876a..66df4a6e46 100644
--- a/web/core/modules/views/src/Plugin/views/cache/CachePluginBase.php
+++ b/web/core/modules/views/src/Plugin/views/cache/CachePluginBase.php
@@ -214,7 +214,7 @@ public function generateResultsKey() {
         'build_info' => $build_info,
       ];
       // @todo https://www.drupal.org/node/2433591 might solve it to not require
-      //    the pager information here.
+      //   the pager information here.
       $key_data['pager'] = [
         'page' => $this->view->getCurrentPage(),
         'items_per_page' => $this->view->getItemsPerPage(),
diff --git a/web/core/modules/views/src/Plugin/views/field/EntityField.php b/web/core/modules/views/src/Plugin/views/field/EntityField.php
index 95d1ebde90..7957cb054c 100644
--- a/web/core/modules/views/src/Plugin/views/field/EntityField.php
+++ b/web/core/modules/views/src/Plugin/views/field/EntityField.php
@@ -320,8 +320,12 @@ public function clickSort($order) {
     $field_storage_definition = $this->getFieldStorageDefinition();
     $column = $this->getTableMapping()->getFieldColumnName($field_storage_definition, $this->options['click_sort_column']);
     if (!isset($this->aliases[$column])) {
-      // Column is not in query; add a sort on it (without adding the column).
+      // Column is not in query; add a sort on it.
       $this->aliases[$column] = $this->tableAlias . '.' . $column;
+      // If the query uses DISTINCT we need to add the column too.
+      if (!empty($this->view->getQuery()->options['distinct'])) {
+        $this->query->addField($this->tableAlias, $column);
+      }
     }
     $this->query->addOrderBy(NULL, NULL, $order, $this->aliases[$column]);
   }
diff --git a/web/core/modules/views/src/Plugin/views/join/Subquery.php b/web/core/modules/views/src/Plugin/views/join/Subquery.php
index f407ffce33..8ef5342d10 100644
--- a/web/core/modules/views/src/Plugin/views/join/Subquery.php
+++ b/web/core/modules/views/src/Plugin/views/join/Subquery.php
@@ -52,7 +52,7 @@ public function buildJoin($select_query, $table, $view_query) {
 
     // Tack on the extra.
     // This is just copied verbatim from the parent class, which itself has a
-    //   bug: https://www.drupal.org/node/1118100.
+    // bug: https://www.drupal.org/node/1118100.
     if (isset($this->extra)) {
       if (is_array($this->extra)) {
         $extras = [];
diff --git a/web/core/modules/views/src/Plugin/views/query/Sql.php b/web/core/modules/views/src/Plugin/views/query/Sql.php
index 96968b5e32..c6200bc16a 100644
--- a/web/core/modules/views/src/Plugin/views/query/Sql.php
+++ b/web/core/modules/views/src/Plugin/views/query/Sql.php
@@ -834,7 +834,7 @@ public function addField($table, $field, $alias = '', $params = []) {
     $alias = $alias ? $alias : $field;
 
     // PostgreSQL truncates aliases to 63 characters:
-    //   https://www.drupal.org/node/571548.
+    // https://www.drupal.org/node/571548.
 
     // We limit the length of the original alias up to 60 characters
     // to get a unique alias later if its have duplicates
diff --git a/web/core/modules/views/src/ViewExecutable.php b/web/core/modules/views/src/ViewExecutable.php
index 5abd76d184..7637ec8f74 100644
--- a/web/core/modules/views/src/ViewExecutable.php
+++ b/web/core/modules/views/src/ViewExecutable.php
@@ -1467,7 +1467,7 @@ public function render($display_id = NULL) {
 
     $module_handler = \Drupal::moduleHandler();
 
-    // @TODO In the longrun, it would be great to execute a view without
+    // @todo In the long run, it would be great to execute a view without
     //   the theme system at all. See https://www.drupal.org/node/2322623.
     $active_theme = \Drupal::theme()->getActiveTheme();
     $themes = array_keys($active_theme->getBaseThemeExtensions());
diff --git a/web/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_distinct_click_sorting.yml b/web/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_distinct_click_sorting.yml
new file mode 100644
index 0000000000..55813bc9c4
--- /dev/null
+++ b/web/core/modules/views/tests/modules/views_test_config/test_views/views.view.test_distinct_click_sorting.yml
@@ -0,0 +1,263 @@
+langcode: en
+status: true
+dependencies:
+  module:
+    - node
+    - user
+id: test_distinct_click_sorting
+label: 'test_distinct_click_sorting'
+module: views
+description: ''
+tag: ''
+base_table: node_field_data
+base_field: nid
+display:
+  default:
+    display_plugin: default
+    id: default
+    display_title: Default
+    position: 0
+    display_options:
+      access:
+        type: perm
+        options:
+          perm: 'access content'
+      cache:
+        type: tag
+        options: {  }
+      query:
+        type: views_query
+        options:
+          disable_sql_rewrite: false
+          distinct: true
+          replica: false
+          query_comment: ''
+          query_tags: {  }
+      exposed_form:
+        type: basic
+        options:
+          submit_button: Apply
+          reset_button: false
+          reset_button_label: Reset
+          exposed_sorts_label: 'Sort by'
+          expose_sort_order: true
+          sort_asc_label: Asc
+          sort_desc_label: Desc
+      pager:
+        type: mini
+        options:
+          items_per_page: 10
+          offset: 0
+          id: 0
+          total_pages: null
+          expose:
+            items_per_page: false
+            items_per_page_label: 'Items per page'
+            items_per_page_options: '5, 10, 25, 50'
+            items_per_page_options_all: false
+            items_per_page_options_all_label: '- All -'
+            offset: false
+            offset_label: Offset
+          tags:
+            previous: ‹‹
+            next: ››
+      style:
+        type: table
+        options:
+          grouping: {  }
+          row_class: ''
+          default_row_class: true
+          override: true
+          sticky: false
+          caption: ''
+          summary: ''
+          description: ''
+          columns:
+            title: title
+            changed: changed
+          info:
+            title:
+              sortable: true
+              default_sort_order: asc
+              align: ''
+              separator: ''
+              empty_column: false
+              responsive: ''
+            changed:
+              sortable: true
+              default_sort_order: asc
+              align: ''
+              separator: ''
+              empty_column: false
+              responsive: ''
+          default: changed
+          empty_table: false
+      row:
+        type: fields
+        options:
+          inline: {  }
+          separator: ''
+          hide_empty: false
+          default_field_elements: true
+      fields:
+        title:
+          id: title
+          table: node_field_data
+          field: title
+          entity_type: node
+          entity_field: title
+          label: ''
+          alter:
+            alter_text: false
+            make_link: false
+            absolute: false
+            trim: false
+            word_boundary: false
+            ellipsis: false
+            strip_tags: false
+            html: false
+          hide_empty: false
+          empty_zero: false
+          settings:
+            link_to_entity: true
+          plugin_id: field
+          relationship: none
+          group_type: group
+          admin_label: ''
+          exclude: false
+          element_type: ''
+          element_class: ''
+          element_label_type: ''
+          element_label_class: ''
+          element_label_colon: true
+          element_wrapper_type: ''
+          element_wrapper_class: ''
+          element_default_classes: true
+          empty: ''
+          hide_alter_empty: true
+          click_sort_column: value
+          type: string
+          group_column: value
+          group_columns: {  }
+          group_rows: true
+          delta_limit: 0
+          delta_offset: 0
+          delta_reversed: false
+          delta_first_last: false
+          multi_type: separator
+          separator: ', '
+          field_api_classes: false
+        changed:
+          id: changed
+          table: node_field_data
+          field: changed
+          relationship: none
+          group_type: group
+          admin_label: ''
+          label: Changed
+          exclude: false
+          alter:
+            alter_text: false
+            text: ''
+            make_link: false
+            path: ''
+            absolute: false
+            external: false
+            replace_spaces: false
+            path_case: none
+            trim_whitespace: false
+            alt: ''
+            rel: ''
+            link_class: ''
+            prefix: ''
+            suffix: ''
+            target: ''
+            nl2br: false
+            max_length: 0
+            word_boundary: true
+            ellipsis: true
+            more_link: false
+            more_link_text: ''
+            more_link_path: ''
+            strip_tags: false
+            trim: false
+            preserve_tags: ''
+            html: false
+          element_type: ''
+          element_class: ''
+          element_label_type: ''
+          element_label_class: ''
+          element_label_colon: true
+          element_wrapper_type: ''
+          element_wrapper_class: ''
+          element_default_classes: true
+          empty: ''
+          hide_empty: false
+          empty_zero: false
+          hide_alter_empty: true
+          click_sort_column: value
+          type: timestamp
+          settings:
+            date_format: medium
+            custom_date_format: ''
+            timezone: ''
+          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: node
+          entity_field: changed
+          plugin_id: field
+      filters:
+        status:
+          value: '1'
+          table: node_field_data
+          field: status
+          plugin_id: boolean
+          entity_type: node
+          entity_field: status
+          id: status
+          expose:
+            operator: ''
+            operator_limit_selection: false
+            operator_list: {  }
+          group: 1
+      sorts: {  }
+      header: {  }
+      footer: {  }
+      empty: {  }
+      relationships: {  }
+      arguments: {  }
+      display_extenders: {  }
+    cache_metadata:
+      max-age: -1
+      contexts:
+        - 'languages:language_content'
+        - 'languages:language_interface'
+        - url.query_args
+        - 'user.node_grants:view'
+        - user.permissions
+      tags: {  }
+  page_1:
+    display_plugin: page
+    id: page_1
+    display_title: Page
+    position: 1
+    display_options:
+      display_extenders: {  }
+      path: test_distinct_click_sorting
+    cache_metadata:
+      max-age: -1
+      contexts:
+        - 'languages:language_content'
+        - 'languages:language_interface'
+        - url.query_args
+        - 'user.node_grants:view'
+        - user.permissions
+      tags: {  }
diff --git a/web/core/modules/views/tests/src/Functional/BulkFormTest.php b/web/core/modules/views/tests/src/Functional/BulkFormTest.php
index 85c0a4c132..4e515c6aa6 100644
--- a/web/core/modules/views/tests/src/Functional/BulkFormTest.php
+++ b/web/core/modules/views/tests/src/Functional/BulkFormTest.php
@@ -132,8 +132,7 @@ public function testBulkForm() {
 
     // Check the default title.
     $this->drupalGet('test_bulk_form');
-    $result = $this->xpath('//label[@for="edit-action"]');
-    $this->assertEquals('Action', $result[0]->getText());
+    $this->assertSession()->elementTextEquals('xpath', '//label[@for="edit-action"]', 'Action');
 
     // Setup up a different bulk form title.
     $view = Views::getView('test_bulk_form');
@@ -142,8 +141,7 @@ public function testBulkForm() {
     $view->save();
 
     $this->drupalGet('test_bulk_form');
-    $result = $this->xpath('//label[@for="edit-action"]');
-    $this->assertEquals('Test title', $result[0]->getText());
+    $this->assertSession()->elementTextEquals('xpath', '//label[@for="edit-action"]', 'Test title');
 
     $this->drupalGet('test_bulk_form');
     // Call the node delete action.
@@ -197,7 +195,7 @@ public function testBulkForm() {
 
     // Test that the bulk form works when multiple nodes are selected
     // but all of the selected nodes are already deleted
-    //  by another user before the loaded bulk form was submitted.
+    // by another user before the loaded bulk form was submitted.
     $this->drupalGet('test_bulk_form');
     // Call the node delete action.
     foreach ($nodes as $key => $node) {
diff --git a/web/core/modules/views/tests/src/Functional/Handler/FieldWebTest.php b/web/core/modules/views/tests/src/Functional/Handler/FieldWebTest.php
index bb7861f5e1..91b9f81882 100644
--- a/web/core/modules/views/tests/src/Functional/Handler/FieldWebTest.php
+++ b/web/core/modules/views/tests/src/Functional/Handler/FieldWebTest.php
@@ -7,6 +7,7 @@
 use Drupal\Component\Utility\UrlHelper;
 use Drupal\Core\Render\RenderContext;
 use Drupal\Core\Url;
+use Drupal\language\Entity\ConfigurableLanguage;
 use Drupal\Tests\system\Functional\Cache\AssertPageCacheContextsAndTagsTrait;
 use Drupal\Tests\views\Functional\ViewTestBase;
 use Drupal\views\Views;
@@ -26,12 +27,12 @@ class FieldWebTest extends ViewTestBase {
    *
    * @var array
    */
-  public static $testViews = ['test_view', 'test_field_classes', 'test_field_output', 'test_click_sort'];
+  public static $testViews = ['test_view', 'test_field_classes', 'test_field_output', 'test_click_sort', 'test_distinct_click_sorting'];
 
   /**
    * {@inheritdoc}
    */
-  protected static $modules = ['node'];
+  protected static $modules = ['node', 'language'];
 
   /**
    * {@inheritdoc}
@@ -99,6 +100,24 @@ public function testClickSorting() {
     $this->assertEquals(range(5, 1, -1), $ids);
   }
 
+  /**
+   * Tests the default click sorting functionality with distinct.
+   */
+  public function testClickSortingDistinct() {
+    ConfigurableLanguage::createFromLangcode('es')->save();
+    $node = $this->drupalCreateNode();
+    $this->drupalGet('test_distinct_click_sorting');
+    $this->assertSession()->statusCodeEquals(200);
+
+    // Check that the results are ordered by id in ascending order and that the
+    // title click filter is for descending.
+    $this->assertSession()->linkByHrefExists(Url::fromRoute('<none>', [], ['query' => ['order' => 'changed', 'sort' => 'desc']])->toString());
+    $this->assertSession()->pageTextContains($node->getTitle());
+    $this->clickLink('Changed');
+    $this->assertSession()->statusCodeEquals(200);
+    $this->assertSession()->pageTextContains($node->getTitle());
+  }
+
   /**
    * Small helper function to get all ids in the output.
    *
diff --git a/web/core/modules/views/tests/src/Functional/Plugin/PagerTest.php b/web/core/modules/views/tests/src/Functional/Plugin/PagerTest.php
index a4bf0f55b7..71d2b97ba2 100644
--- a/web/core/modules/views/tests/src/Functional/Plugin/PagerTest.php
+++ b/web/core/modules/views/tests/src/Functional/Plugin/PagerTest.php
@@ -57,7 +57,7 @@ public function testStorePagerSettings() {
     ]);
     $this->drupalLogin($admin_user);
     // Test behavior described in
-    //   https://www.drupal.org/node/652712#comment-2354918.
+    // https://www.drupal.org/node/652712#comment-2354918.
 
     $this->drupalGet('admin/structure/views/view/test_view/edit');
 
@@ -136,7 +136,7 @@ public function testStorePagerSettings() {
     $this->assertSession()->pageTextContains('Mini');
 
     // Test behavior described in
-    //   https://www.drupal.org/node/652712#comment-2354400.
+    // https://www.drupal.org/node/652712#comment-2354400.
     $view = Views::getView('test_store_pager_settings');
     // Make it editable in the admin interface.
     $view->save();
diff --git a/web/core/modules/views/tests/src/Kernel/Entity/FilterEntityBundleTest.php b/web/core/modules/views/tests/src/Kernel/Entity/FilterEntityBundleTest.php
index 19c9e5bde3..25faf55edf 100644
--- a/web/core/modules/views/tests/src/Kernel/Entity/FilterEntityBundleTest.php
+++ b/web/core/modules/views/tests/src/Kernel/Entity/FilterEntityBundleTest.php
@@ -88,7 +88,7 @@ public function testFilterEntity() {
       $view->display_handler->setOption('filters', $filters);
       $this->executeView($view);
 
-      $this->assertCount(count($entities[$key]), $view->result);
+      $this->assertSameSize($entities[$key], $view->result);
 
       $view->destroy();
     }
diff --git a/web/core/modules/views/tests/src/Kernel/Entity/LatestRevisionFilterTest.php b/web/core/modules/views/tests/src/Kernel/Entity/LatestRevisionFilterTest.php
index a29f589a79..1b47f80b4e 100644
--- a/web/core/modules/views/tests/src/Kernel/Entity/LatestRevisionFilterTest.php
+++ b/web/core/modules/views/tests/src/Kernel/Entity/LatestRevisionFilterTest.php
@@ -100,7 +100,7 @@ public function testLatestRevisionFilter() {
     $this->executeView($view);
 
     // Check that we have all the results.
-    $this->assertCount(count($latest_revisions), $view->result);
+    $this->assertSameSize($latest_revisions, $view->result);
 
     $expected = $not_expected = [];
     foreach ($all_revisions as $revision_id => $revision) {
diff --git a/web/core/modules/views/tests/src/Kernel/Handler/SortRandomTest.php b/web/core/modules/views/tests/src/Kernel/Handler/SortRandomTest.php
index a7593381b8..a1ad7d31d9 100644
--- a/web/core/modules/views/tests/src/Kernel/Handler/SortRandomTest.php
+++ b/web/core/modules/views/tests/src/Kernel/Handler/SortRandomTest.php
@@ -75,7 +75,7 @@ public function testRandomOrdering() {
     $this->executeView($view);
 
     // Verify the result.
-    $this->assertSame(count($this->dataSet()), count($view->result), 'The number of returned rows match.');
+    $this->assertSameSize($this->dataSet(), $view->result, 'The number of returned rows match.');
     $this->assertIdenticalResultset($view, $this->dataSet(), [
       'views_test_data_name' => 'name',
       'views_test_data_age' => 'age',
@@ -84,7 +84,7 @@ public function testRandomOrdering() {
     // Execute a random view, we expect the result set to be different.
     $view_random = $this->getBasicRandomView();
     $this->executeView($view_random);
-    $this->assertSame(count($this->dataSet()), count($view_random->result), 'The number of returned rows match.');
+    $this->assertSameSize($this->dataSet(), $view_random->result, 'The number of returned rows match.');
     $this->assertNotIdenticalResultset($view_random, $view->result, [
       'views_test_data_name' => 'views_test_data_name',
       'views_test_data_age' => 'views_test_data_name',
@@ -93,7 +93,7 @@ public function testRandomOrdering() {
     // Execute a second random view, we expect the result set to be different again.
     $view_random_2 = $this->getBasicRandomView();
     $this->executeView($view_random_2);
-    $this->assertSame(count($this->dataSet()), count($view_random_2->result), 'The number of returned rows match.');
+    $this->assertSameSize($this->dataSet(), $view_random_2->result, 'The number of returned rows match.');
     $this->assertNotIdenticalResultset($view_random, $view->result, [
       'views_test_data_name' => 'views_test_data_name',
       'views_test_data_age' => 'views_test_data_name',
diff --git a/web/core/modules/views/tests/src/Kernel/Handler/SortTest.php b/web/core/modules/views/tests/src/Kernel/Handler/SortTest.php
index 7ab0fb8079..3fa1b63e06 100644
--- a/web/core/modules/views/tests/src/Kernel/Handler/SortTest.php
+++ b/web/core/modules/views/tests/src/Kernel/Handler/SortTest.php
@@ -41,7 +41,7 @@ public function testNumericOrdering() {
     $this->executeView($view);
 
     // Verify the result.
-    $this->assertSame(count($this->dataSet()), count($view->result), 'The number of returned rows match.');
+    $this->assertSameSize($this->dataSet(), $view->result, 'The number of returned rows match.');
     $this->assertIdenticalResultset($view, $this->orderResultSet($this->dataSet(), 'age'), [
       'views_test_data_name' => 'name',
       'views_test_data_age' => 'age',
@@ -65,7 +65,7 @@ public function testNumericOrdering() {
     $this->executeView($view);
 
     // Verify the result.
-    $this->assertSame(count($this->dataSet()), count($view->result), 'The number of returned rows match.');
+    $this->assertSameSize($this->dataSet(), $view->result, 'The number of returned rows match.');
     $this->assertIdenticalResultset($view, $this->orderResultSet($this->dataSet(), 'age', TRUE), [
       'views_test_data_name' => 'name',
       'views_test_data_age' => 'age',
@@ -94,7 +94,7 @@ public function testStringOrdering() {
     $this->executeView($view);
 
     // Verify the result.
-    $this->assertSame(count($this->dataSet()), count($view->result), 'The number of returned rows match.');
+    $this->assertSameSize($this->dataSet(), $view->result, 'The number of returned rows match.');
     $this->assertIdenticalResultset($view, $this->orderResultSet($this->dataSet(), 'name'), [
       'views_test_data_name' => 'name',
       'views_test_data_age' => 'age',
@@ -118,7 +118,7 @@ public function testStringOrdering() {
     $this->executeView($view);
 
     // Verify the result.
-    $this->assertSame(count($this->dataSet()), count($view->result), 'The number of returned rows match.');
+    $this->assertSameSize($this->dataSet(), $view->result, 'The number of returned rows match.');
     $this->assertIdenticalResultset($view, $this->orderResultSet($this->dataSet(), 'name', TRUE), [
       'views_test_data_name' => 'name',
       'views_test_data_age' => 'age',
diff --git a/web/core/modules/views/tests/src/Unit/ViewExecutableTest.php b/web/core/modules/views/tests/src/Unit/ViewExecutableTest.php
index 8746dee665..f24c0d1428 100644
--- a/web/core/modules/views/tests/src/Unit/ViewExecutableTest.php
+++ b/web/core/modules/views/tests/src/Unit/ViewExecutableTest.php
@@ -344,8 +344,8 @@ public function testBuildThemeFunctions() {
   public function testGenerateHandlerId() {
     // Test the generateHandlerId() method.
     $test_ids = ['test' => 'test', 'test_1' => 'test_1'];
-    $this->assertEquals(ViewExecutable::generateHandlerId('new', $test_ids), 'new');
-    $this->assertEquals(ViewExecutable::generateHandlerId('test', $test_ids), 'test_2');
+    $this->assertEquals('new', ViewExecutable::generateHandlerId('new', $test_ids));
+    $this->assertEquals('test_2', ViewExecutable::generateHandlerId('test', $test_ids));
   }
 
   /**
diff --git a/web/core/modules/views/tests/src/Unit/ViewsDataTest.php b/web/core/modules/views/tests/src/Unit/ViewsDataTest.php
index b4ee79b529..8a501ec789 100644
--- a/web/core/modules/views/tests/src/Unit/ViewsDataTest.php
+++ b/web/core/modules/views/tests/src/Unit/ViewsDataTest.php
@@ -133,11 +133,11 @@ protected function viewsDataWithProvider() {
    */
   protected function setupMockedModuleHandler() {
     $views_data = $this->viewsData();
-    $this->moduleHandler->expects($this->at(0))
+    $this->moduleHandler->expects($this->once())
       ->method('getImplementations')
       ->with('views_data')
       ->willReturn(['views_test_data']);
-    $this->moduleHandler->expects($this->at(1))
+    $this->moduleHandler->expects($this->once())
       ->method('invoke')
       ->with('views_test_data', 'views_data')
       ->willReturn($views_data);
@@ -188,7 +188,7 @@ public function testGetOnFirstCall() {
     // Ensure that the hooks are just invoked once.
     $this->setupMockedModuleHandler();
 
-    $this->moduleHandler->expects($this->at(2))
+    $this->moduleHandler->expects($this->once())
       ->method('alter')
       ->with('views_data', $this->viewsDataWithProvider());
 
@@ -212,63 +212,40 @@ public function testFullAndTableGetCache() {
     $random_table_name = $this->randomMachineName();
 
     // Views data should be invoked twice due to the clear call.
-    $this->moduleHandler->expects($this->at(0))
-      ->method('getImplementations')
-      ->with('views_data')
-      ->willReturn(['views_test_data']);
-    $this->moduleHandler->expects($this->at(1))
-      ->method('invoke')
-      ->with('views_test_data', 'views_data')
-      ->willReturn($this->viewsData());
-    $this->moduleHandler->expects($this->at(2))
-      ->method('alter')
-      ->with('views_data', $expected_views_data);
-
-    $this->moduleHandler->expects($this->at(3))
+    $this->moduleHandler->expects($this->exactly(2))
       ->method('getImplementations')
       ->with('views_data')
       ->willReturn(['views_test_data']);
-    $this->moduleHandler->expects($this->at(4))
+    $this->moduleHandler->expects($this->exactly(2))
       ->method('invoke')
       ->with('views_test_data', 'views_data')
       ->willReturn($this->viewsData());
-    $this->moduleHandler->expects($this->at(5))
+    $this->moduleHandler->expects($this->exactly(2))
       ->method('alter')
       ->with('views_data', $expected_views_data);
 
     // The cache should only be called once (before the clear() call) as get
     // will get all table data in the first get().
-    $this->cacheBackend->expects($this->at(0))
+    $this->cacheBackend->expects($this->exactly(4))
       ->method('get')
-      ->with("views_data:en")
-      ->will($this->returnValue(FALSE));
-    $this->cacheBackend->expects($this->at(1))
-      ->method('set')
-      ->with("views_data:en", $expected_views_data);
-    $this->cacheBackend->expects($this->at(2))
-      ->method('get')
-      ->with("views_data:$random_table_name:en")
-      ->will($this->returnValue(FALSE));
-    $this->cacheBackend->expects($this->at(3))
+      ->withConsecutive(
+        ['views_data:en'],
+        ["views_data:$random_table_name:en"],
+        ['views_data:en'],
+        ["views_data:$random_table_name:en"],
+      )
+      ->willReturn(FALSE);
+    $this->cacheBackend->expects($this->exactly(4))
       ->method('set')
-      ->with("views_data:$random_table_name:en", []);
+      ->withConsecutive(
+        ['views_data:en', $expected_views_data],
+        ["views_data:$random_table_name:en", []],
+        ['views_data:en', $expected_views_data],
+        ["views_data:$random_table_name:en", []],
+      );
     $this->cacheTagsInvalidator->expects($this->once())
       ->method('invalidateTags')
       ->with(['views_data']);
-    $this->cacheBackend->expects($this->at(4))
-      ->method('get')
-      ->with("views_data:en")
-      ->will($this->returnValue(FALSE));
-    $this->cacheBackend->expects($this->at(5))
-      ->method('set')
-      ->with("views_data:en", $expected_views_data);
-    $this->cacheBackend->expects($this->at(6))
-      ->method('get')
-      ->with("views_data:$random_table_name:en")
-      ->will($this->returnValue(FALSE));
-    $this->cacheBackend->expects($this->at(7))
-      ->method('set')
-      ->with("views_data:$random_table_name:en", []);
 
     $views_data = $this->viewsData->getAll();
     $this->assertSame($expected_views_data, $views_data);
@@ -332,14 +309,13 @@ public function testSingleTableGetCache() {
       ->method('alter')
       ->with('views_data', $this->viewsDataWithProvider());
 
-    $this->cacheBackend->expects($this->at(0))
+    $this->cacheBackend->expects($this->exactly(2))
       ->method('get')
-      ->with("views_data:$table_name:en")
-      ->will($this->returnValue(FALSE));
-    $this->cacheBackend->expects($this->at(1))
-      ->method('get')
-      ->with("views_data:en")
-      ->will($this->returnValue(FALSE));
+      ->withConsecutive(
+        ["views_data:$table_name:en"],
+        ['views_data:en'],
+      )
+      ->willReturn(FALSE);
 
     $views_data = $this->viewsData->get($table_name);
     $this->assertSame($expected_views_data[$table_name], $views_data, 'Make sure fetching views data by table works as expected.');
@@ -367,14 +343,13 @@ public function testNonExistingTableGetCache() {
       ->method('alter')
       ->with('views_data', $this->viewsDataWithProvider());
 
-    $this->cacheBackend->expects($this->at(0))
-      ->method('get')
-      ->with("views_data:$random_table_name:en")
-      ->will($this->returnValue(FALSE));
-    $this->cacheBackend->expects($this->at(1))
+    $this->cacheBackend->expects($this->exactly(2))
       ->method('get')
-      ->with("views_data:en")
-      ->will($this->returnValue(FALSE));
+      ->withConsecutive(
+        ["views_data:$random_table_name:en"],
+        ['views_data:en'],
+      )
+      ->willReturn(FALSE);
 
     // All views data should be requested on the first try.
     $views_data = $this->viewsData->get($random_table_name);
@@ -393,18 +368,18 @@ public function testCacheCallsWithSameTableMultipleTimes() {
 
     $this->setupMockedModuleHandler();
 
-    $this->cacheBackend->expects($this->at(0))
-      ->method('get')
-      ->with('views_data:views_test_data:en');
-    $this->cacheBackend->expects($this->at(1))
+    $this->cacheBackend->expects($this->exactly(2))
       ->method('get')
-      ->with('views_data:en');
-    $this->cacheBackend->expects($this->at(2))
+      ->withConsecutive(
+        ['views_data:views_test_data:en'],
+        ['views_data:en'],
+      );
+    $this->cacheBackend->expects($this->exactly(2))
       ->method('set')
-      ->with('views_data:en', $expected_views_data);
-    $this->cacheBackend->expects($this->at(3))
-      ->method('set')
-      ->with('views_data:views_test_data:en', $expected_views_data['views_test_data']);
+      ->withConsecutive(
+        ['views_data:en', $expected_views_data],
+        ['views_data:views_test_data:en', $expected_views_data['views_test_data']],
+      );
 
     // Request the same table 5 times. The caches are empty at this point, so
     // what will happen is that it will first check for a cache entry for the
@@ -461,14 +436,17 @@ public function testCacheCallsWithWarmCacheAndDifferentTable() {
       ->method('getImplementations');
 
     // Setup a warm cache backend for a single table.
-    $this->cacheBackend->expects($this->at(0))
-      ->method('get')
-      ->with('views_data:views_test_data_2:en');
-    $this->cacheBackend->expects($this->at(1))
+    $this->cacheBackend->expects($this->exactly(2))
       ->method('get')
-      ->with('views_data:en')
-      ->will($this->returnValue((object) ['data' => $expected_views_data]));
-    $this->cacheBackend->expects($this->at(2))
+      ->withConsecutive(
+        ['views_data:views_test_data_2:en'],
+        ['views_data:en'],
+      )
+      ->willReturnOnConsecutiveCalls(
+        FALSE,
+        (object) ['data' => $expected_views_data],
+      );
+    $this->cacheBackend->expects($this->once())
       ->method('set')
       ->with('views_data:views_test_data_2:en', $expected_views_data['views_test_data_2']);
 
@@ -497,14 +475,17 @@ public function testCacheCallsWithWarmCacheAndInvalidTable() {
       ->method('getImplementations');
 
     // Setup a warm cache backend for a single table.
-    $this->cacheBackend->expects($this->at(0))
-      ->method('get')
-      ->with("views_data:$non_existing_table:en");
-    $this->cacheBackend->expects($this->at(1))
+    $this->cacheBackend->expects($this->exactly(2))
       ->method('get')
-      ->with('views_data:en')
-      ->will($this->returnValue((object) ['data' => $expected_views_data]));
-    $this->cacheBackend->expects($this->at(2))
+      ->withConsecutive(
+        ["views_data:$non_existing_table:en"],
+        ['views_data:en'],
+      )
+      ->willReturnOnConsecutiveCalls(
+        FALSE,
+        (object) ['data' => $expected_views_data],
+      );
+    $this->cacheBackend->expects($this->once())
       ->method('set')
       ->with("views_data:$non_existing_table:en", []);
 
@@ -612,24 +593,24 @@ public function testCacheCallsWithoutWarmCacheAndGetMultipleTables() {
     $table_name_2 = 'views_test_data_2';
 
     // Setup a warm cache backend for all table data, but not single tables.
-    $this->cacheBackend->expects($this->at(0))
+    $this->cacheBackend->expects($this->exactly(3))
       ->method('get')
-      ->with("views_data:$table_name:en")
-      ->will($this->returnValue(FALSE));
-    $this->cacheBackend->expects($this->at(1))
-      ->method('get')
-      ->with('views_data:en')
-      ->will($this->returnValue((object) ['data' => $expected_views_data]));
-    $this->cacheBackend->expects($this->at(2))
-      ->method('set')
-      ->with("views_data:$table_name:en", $expected_views_data[$table_name]);
-    $this->cacheBackend->expects($this->at(3))
-      ->method('get')
-      ->with("views_data:$table_name_2:en")
-      ->will($this->returnValue(FALSE));
-    $this->cacheBackend->expects($this->at(4))
+      ->withConsecutive(
+        ["views_data:$table_name:en"],
+        ['views_data:en'],
+        ["views_data:$table_name_2:en"],
+      )
+      ->willReturnOnConsecutiveCalls(
+        FALSE,
+        (object) ['data' => $expected_views_data],
+        FALSE,
+      );
+    $this->cacheBackend->expects($this->exactly(2))
       ->method('set')
-      ->with("views_data:$table_name_2:en", $expected_views_data[$table_name_2]);
+      ->withConsecutive(
+        ["views_data:$table_name:en", $expected_views_data[$table_name]],
+        ["views_data:$table_name_2:en", $expected_views_data[$table_name_2]],
+      );
 
     $this->assertSame($expected_views_data[$table_name], $this->viewsData->get($table_name));
     $this->assertSame($expected_views_data[$table_name_2], $this->viewsData->get($table_name_2));
diff --git a/web/core/modules/views/views.api.php b/web/core/modules/views/views.api.php
index e9b7513ab4..215c8ec094 100644
--- a/web/core/modules/views/views.api.php
+++ b/web/core/modules/views/views.api.php
@@ -133,6 +133,7 @@ function hook_views_analyze(\Drupal\views\ViewExecutable $view) {
 function hook_views_data() {
   // This example describes how to write hook_views_data() for a table defined
   // like this:
+  // @code
   // CREATE TABLE example_table (
   //   nid INT(11) NOT NULL         COMMENT 'Primary key: {node}.nid.',
   //   plain_text_field VARCHAR(32) COMMENT 'Just a plain text field.',
@@ -142,6 +143,7 @@ function hook_views_data() {
   //   langcode VARCHAR(12)         COMMENT 'Language code field.',
   //   PRIMARY KEY(nid)
   // );
+  // @endcode
 
   // Define the return array.
   $data = [];
@@ -193,8 +195,10 @@ function hook_views_data() {
   //
   // If you've decided an automatic join is a good idea, here's how to do it;
   // the resulting SQL query will look something like this:
+  // @code
   //   ... FROM example_table et ... JOIN node_field_data nfd
   //   ON et.nid = nfd.nid AND ('extra' clauses will be here) ...
+  // @endcode
   // although the table aliases will be different.
   $data['example_table']['table']['join'] = [
     // Within the 'join' section, list one or more tables to automatically
@@ -243,10 +247,12 @@ function hook_views_data() {
   // shown above), you could join to 'node_field_table' via the 'foo' table.
   // Here's how to do this, and the resulting SQL query would look something
   // like this:
+  // @code
   //   ... FROM example_table et ... JOIN foo foo
   //   ON et.nid = foo.nid AND ('extra' clauses will be here) ...
   //   JOIN node_field_data nfd ON (definition of the join from the foo
   //   module goes here) ...
+  // @endcode
   // although the table aliases will be different.
   $data['example_table']['table']['join']['node_field_data'] = [
     // 'node_field_data' above is the base we're joining to in Views.
@@ -865,7 +871,7 @@ function hook_views_post_render(ViewExecutable $view, &$output, CachePluginBase
  *
  * @param \Drupal\views\ViewExecutable $view
  *   The view object about to be processed.
- * @param QueryPluginBase $query
+ * @param \Drupal\views\Plugin\views\query\QueryPluginBase $query
  *   The query plugin object for the query.
  *
  * @see hook_views_query_substitutions()
diff --git a/web/core/modules/views_ui/tests/src/Functional/FilterNumericWebTest.php b/web/core/modules/views_ui/tests/src/Functional/FilterNumericWebTest.php
index 43093efbf3..eea148bdaa 100644
--- a/web/core/modules/views_ui/tests/src/Functional/FilterNumericWebTest.php
+++ b/web/core/modules/views_ui/tests/src/Functional/FilterNumericWebTest.php
@@ -123,12 +123,10 @@ public function testFilterNumericUI() {
     // Check the field (wrapper) label.
     $this->assertSession()->elementTextContains('css', 'fieldset#edit-age-wrapper legend', 'Age between');
     // Check the min/max labels.
-    $min_element_label = $this->xpath('//fieldset[contains(@id, "edit-age-wrapper")]//label[contains(@for, "edit-age-min") and contains(text(), "Min")]');
-    $this->assertCount(1, $min_element_label);
-    $max_element_label = $this->xpath('//fieldset[contains(@id, "edit-age-wrapper")]//label[contains(@for, "edit-age-max") and contains(text(), "Max")]');
-    $this->assertCount(1, $max_element_label);
+    $this->assertSession()->elementsCount('xpath', '//fieldset[contains(@id, "edit-age-wrapper")]//label[contains(@for, "edit-age-min") and contains(text(), "Min")]', 1);
+    $this->assertSession()->elementsCount('xpath', '//fieldset[contains(@id, "edit-age-wrapper")]//label[contains(@for, "edit-age-max") and contains(text(), "Max")]', 1);
     // Check that the description is shown in the right place.
-    $this->assertEquals(trim($this->cssSelect('#edit-age-wrapper--description')[0]->getText()), 'Description of the exposed filter');
+    $this->assertEquals('Description of the exposed filter', trim($this->cssSelect('#edit-age-wrapper--description')[0]->getText()));
 
     // Change to an operation that only requires one form element ('>').
     $this->drupalGet('admin/structure/views/nojs/handler/test_view/default/filter/age');
@@ -145,8 +143,7 @@ public function testFilterNumericUI() {
     $this->submitForm([], 'Update preview');
 
     // Make sure the label is visible and that there's no fieldset wrapper.
-    $label = $this->xpath('//label[contains(@for, "edit-age") and contains(text(), "Age greater than")]');
-    $this->assertCount(1, $label);
+    $this->assertSession()->elementsCount('xpath', '//label[contains(@for, "edit-age") and contains(text(), "Age greater than")]', 1);
     $fieldset = $this->xpath('//fieldset[contains(@id, "edit-age-wrapper")]');
     $this->assertEmpty($fieldset);
   }
diff --git a/web/core/profiles/demo_umami/themes/umami/css/base.css b/web/core/profiles/demo_umami/themes/umami/css/base.css
index c5ae295fff..53443d5b59 100644
--- a/web/core/profiles/demo_umami/themes/umami/css/base.css
+++ b/web/core/profiles/demo_umami/themes/umami/css/base.css
@@ -115,6 +115,7 @@ button:focus,
   transition: background-color 0.5s ease;
   text-decoration: none;
   color: #000;
+  border: 2px solid #008068;
   background-color: #e6eee0;
 }
 button[disabled]:hover,
diff --git a/web/core/tests/Drupal/BuildTests/Composer/Template/ComposerProjectTemplatesTest.php b/web/core/tests/Drupal/BuildTests/Composer/Template/ComposerProjectTemplatesTest.php
index e3cabaffd9..5b341db413 100644
--- a/web/core/tests/Drupal/BuildTests/Composer/Template/ComposerProjectTemplatesTest.php
+++ b/web/core/tests/Drupal/BuildTests/Composer/Template/ComposerProjectTemplatesTest.php
@@ -111,7 +111,7 @@ public function testVerifyTemplateTestProviderIsAccurate() {
     // Find all the templates.
     $template_files = Composer::composerSubprojectPaths($root, 'Template');
 
-    $this->assertSame(count($template_files), count($data));
+    $this->assertSameSize($template_files, $data);
 
     // We could have the same number of templates but different names.
     $template_data = [];
diff --git a/web/core/tests/Drupal/FunctionalTests/BrowserTestBaseTest.php b/web/core/tests/Drupal/FunctionalTests/BrowserTestBaseTest.php
index 4605491eb1..00fa980e97 100644
--- a/web/core/tests/Drupal/FunctionalTests/BrowserTestBaseTest.php
+++ b/web/core/tests/Drupal/FunctionalTests/BrowserTestBaseTest.php
@@ -57,6 +57,9 @@ public function testGoTo() {
     $text = $this->getTextContent();
     $this->assertStringContainsString('Test page text.', $text);
     $this->assertStringNotContainsString('</html>', $text);
+    // Ensure Drupal Javascript settings are not part of the page text.
+    $this->assertArrayHasKey('currentPathIsAdmin', $this->getDrupalSettings()['path']);
+    $this->assertStringNotContainsString('currentPathIsAdmin', $text);
 
     // Response includes cache tags that we can assert.
     $this->assertSession()->responseHeaderExists('X-Drupal-Cache-Tags');
@@ -999,4 +1002,14 @@ public function testVarDump() {
     $this->assertStringContainsString('</samp>}', $body);
   }
 
+  /**
+   * Test if setting an invalid scheme in SIMPLETEST_BASE_URL throws an exception.
+   */
+  public function testSimpleTestBaseUrlValidation() {
+    putenv('SIMPLETEST_BASE_URL=mysql://user:pass@localhost/database');
+    $this->expectException(\Exception::class);
+    $this->expectExceptionMessage('You must provide valid scheme for the SIMPLETEST_BASE_URL environment variable. Valid schema are: http, https.');
+    $this->setupBaseUrl();
+  }
+
 }
diff --git a/web/core/tests/Drupal/FunctionalTests/Entity/ContentEntityFormCorrectUserInputMappingOnFieldDeltaElementsTest.php b/web/core/tests/Drupal/FunctionalTests/Entity/ContentEntityFormCorrectUserInputMappingOnFieldDeltaElementsTest.php
index 39176200f7..1cd176328f 100644
--- a/web/core/tests/Drupal/FunctionalTests/Entity/ContentEntityFormCorrectUserInputMappingOnFieldDeltaElementsTest.php
+++ b/web/core/tests/Drupal/FunctionalTests/Entity/ContentEntityFormCorrectUserInputMappingOnFieldDeltaElementsTest.php
@@ -114,10 +114,10 @@ public function testCorrectUserInputMappingOnComplexFields() {
 
     // Assert that after rearranging the field items the user input will be
     // mapped on the correct delta field items.
-    $this->assertEquals($entity->get($this->fieldName)->getValue(), [
+    $this->assertEquals([
       ['shape' => 'circle', 'color' => 'blue'],
       ['shape' => 'rectangle', 'color' => 'green'],
-    ]);
+    ], $entity->get($this->fieldName)->getValue());
   }
 
 }
diff --git a/web/core/tests/Drupal/FunctionalTests/Installer/InstallerNonDefaultDatabaseDriverTest.php b/web/core/tests/Drupal/FunctionalTests/Installer/InstallerNonDefaultDatabaseDriverTest.php
index 71a42b7796..c7e4dff8b8 100644
--- a/web/core/tests/Drupal/FunctionalTests/Installer/InstallerNonDefaultDatabaseDriverTest.php
+++ b/web/core/tests/Drupal/FunctionalTests/Installer/InstallerNonDefaultDatabaseDriverTest.php
@@ -35,10 +35,8 @@ protected function setUpSettings() {
     $this->testDriverName = 'Drivertest' . ucfirst($driver);
 
     // Assert that we are using the database drivers from the driver_test module.
-    $elements = $this->xpath('//label[@for="edit-driver-drivertestmysql"]');
-    $this->assertEquals('MySQL by the driver_test module', current($elements)->getText());
-    $elements = $this->xpath('//label[@for="edit-driver-drivertestpgsql"]');
-    $this->assertEquals('PostgreSQL by the driver_test module', current($elements)->getText());
+    $this->assertSession()->elementTextEquals('xpath', '//label[@for="edit-driver-drivertestmysql"]', 'MySQL by the driver_test module');
+    $this->assertSession()->elementTextEquals('xpath', '//label[@for="edit-driver-drivertestpgsql"]', 'PostgreSQL by the driver_test module');
 
     $settings = $this->parameters['forms']['install_settings_form'];
 
diff --git a/web/core/tests/Drupal/FunctionalTests/Installer/InstallerTest.php b/web/core/tests/Drupal/FunctionalTests/Installer/InstallerTest.php
index e8e929a020..868560ca83 100644
--- a/web/core/tests/Drupal/FunctionalTests/Installer/InstallerTest.php
+++ b/web/core/tests/Drupal/FunctionalTests/Installer/InstallerTest.php
@@ -88,10 +88,8 @@ protected function setUpSettings() {
 
     // Assert that we use the by core supported database drivers by default and
     // not the ones from the driver_test module.
-    $elements = $this->xpath('//label[@for="edit-driver-mysql"]');
-    $this->assertEquals('MySQL, MariaDB, Percona Server, or equivalent', current($elements)->getText());
-    $elements = $this->xpath('//label[@for="edit-driver-pgsql"]');
-    $this->assertEquals('PostgreSQL', current($elements)->getText());
+    $this->assertSession()->elementTextEquals('xpath', '//label[@for="edit-driver-mysql"]', 'MySQL, MariaDB, Percona Server, or equivalent');
+    $this->assertSession()->elementTextEquals('xpath', '//label[@for="edit-driver-pgsql"]', 'PostgreSQL');
 
     parent::setUpSettings();
   }
diff --git a/web/core/tests/Drupal/FunctionalTests/Update/UpdatePathTestBase.php b/web/core/tests/Drupal/FunctionalTests/Update/UpdatePathTestBase.php
index 23614c7a0e..fa0ba28ed7 100644
--- a/web/core/tests/Drupal/FunctionalTests/Update/UpdatePathTestBase.php
+++ b/web/core/tests/Drupal/FunctionalTests/Update/UpdatePathTestBase.php
@@ -301,7 +301,7 @@ protected function runDbTasks() {
    */
   protected function replaceUser1() {
     /** @var \Drupal\user\UserInterface $account */
-    // @todo: Saving the account before the update is problematic.
+    // @todo Saving the account before the update is problematic.
     //   https://www.drupal.org/node/2560237
     $account = User::load(1);
     $account->setPassword($this->rootUser->pass_raw);
diff --git a/web/core/tests/Drupal/FunctionalTests/Update/UpdatePathTestBaseTest.php b/web/core/tests/Drupal/FunctionalTests/Update/UpdatePathTestBaseTest.php
index fa05eb2c20..925e18922c 100644
--- a/web/core/tests/Drupal/FunctionalTests/Update/UpdatePathTestBaseTest.php
+++ b/web/core/tests/Drupal/FunctionalTests/Update/UpdatePathTestBaseTest.php
@@ -105,7 +105,7 @@ public function testUpdateHookN() {
     // Ensure the index was added for column a.
     $this->assertTrue($connection->schema()->indexExists('update_test_schema_table', 'test'), 'Version 8001 of the update_test_schema module is installed.');
     // Ensure update_test_semver_update_n_update_8001 was run.
-    $this->assertEquals(\Drupal::state()->get('update_test_semver_update_n_update_8001'), 'Yes, I was run. Thanks for testing!');
+    $this->assertEquals('Yes, I was run. Thanks for testing!', \Drupal::state()->get('update_test_semver_update_n_update_8001'));
   }
 
   /**
diff --git a/web/core/tests/Drupal/KernelTests/Core/Action/EmailActionTest.php b/web/core/tests/Drupal/KernelTests/Core/Action/EmailActionTest.php
index 4b1f921358..81d8aad895 100644
--- a/web/core/tests/Drupal/KernelTests/Core/Action/EmailActionTest.php
+++ b/web/core/tests/Drupal/KernelTests/Core/Action/EmailActionTest.php
@@ -57,9 +57,9 @@ public function testEmailAction() {
       ->execute()
       ->fetch();
 
-    $this->assertEquals($log->message, 'Sent email to %recipient');
+    $this->assertEquals('Sent email to %recipient', $log->message);
     $variables = unserialize($log->variables);
-    $this->assertEquals($variables['%recipient'], 'test@example.com');
+    $this->assertEquals('test@example.com', $variables['%recipient']);
   }
 
 }
diff --git a/web/core/tests/Drupal/KernelTests/Core/Config/ExportStorageManagerTest.php b/web/core/tests/Drupal/KernelTests/Core/Config/ExportStorageManagerTest.php
index dbb8db4742..a5e2b3ead4 100644
--- a/web/core/tests/Drupal/KernelTests/Core/Config/ExportStorageManagerTest.php
+++ b/web/core/tests/Drupal/KernelTests/Core/Config/ExportStorageManagerTest.php
@@ -79,17 +79,13 @@ public function testGetStorage() {
    */
   public function testGetStorageLock() {
     $lock = $this->createMock('Drupal\Core\Lock\LockBackendInterface');
-    $lock->expects($this->at(0))
+    $lock->expects($this->exactly(2))
       ->method('acquire')
       ->with(ExportStorageManager::LOCK_NAME)
       ->will($this->returnValue(FALSE));
-    $lock->expects($this->at(1))
+    $lock->expects($this->once())
       ->method('wait')
       ->with(ExportStorageManager::LOCK_NAME);
-    $lock->expects($this->at(2))
-      ->method('acquire')
-      ->with(ExportStorageManager::LOCK_NAME)
-      ->will($this->returnValue(FALSE));
 
     // The export storage manager under test.
     $manager = new ExportStorageManager(
diff --git a/web/core/tests/Drupal/KernelTests/Core/Config/ImportStorageTransformerTest.php b/web/core/tests/Drupal/KernelTests/Core/Config/ImportStorageTransformerTest.php
index 2a06ed69e1..9e637c9c7a 100644
--- a/web/core/tests/Drupal/KernelTests/Core/Config/ImportStorageTransformerTest.php
+++ b/web/core/tests/Drupal/KernelTests/Core/Config/ImportStorageTransformerTest.php
@@ -66,17 +66,13 @@ public function testTransform() {
   public function testTransformLocked() {
     // Mock the request lock not being available.
     $lock = $this->createMock('Drupal\Core\Lock\LockBackendInterface');
-    $lock->expects($this->at(0))
+    $lock->expects($this->exactly(2))
       ->method('acquire')
       ->with(ImportStorageTransformer::LOCK_NAME)
       ->will($this->returnValue(FALSE));
-    $lock->expects($this->at(1))
+    $lock->expects($this->once())
       ->method('wait')
       ->with(ImportStorageTransformer::LOCK_NAME);
-    $lock->expects($this->at(2))
-      ->method('acquire')
-      ->with(ImportStorageTransformer::LOCK_NAME)
-      ->will($this->returnValue(FALSE));
 
     // The import transformer under test.
     $transformer = new ImportStorageTransformer(
@@ -101,7 +97,7 @@ public function testTransformWhileImporting() {
 
     // Mock the persistent lock being unavailable due to a config import.
     $lock = $this->createMock('Drupal\Core\Lock\LockBackendInterface');
-    $lock->expects($this->at(0))
+    $lock->expects($this->once())
       ->method('lockMayBeAvailable')
       ->with(ConfigImporter::LOCK_NAME)
       ->will($this->returnValue(FALSE));
diff --git a/web/core/tests/Drupal/KernelTests/Core/Database/SelectSubqueryTest.php b/web/core/tests/Drupal/KernelTests/Core/Database/SelectSubqueryTest.php
index 102d26c722..496887da35 100644
--- a/web/core/tests/Drupal/KernelTests/Core/Database/SelectSubqueryTest.php
+++ b/web/core/tests/Drupal/KernelTests/Core/Database/SelectSubqueryTest.php
@@ -33,10 +33,12 @@ public function testFromSubquerySelect() {
       $select->condition('task', 'code');
 
       // The resulting query should be equivalent to:
+      // @code
       // SELECT t.name
       // FROM (SELECT tt.pid AS pid, tt.task AS task FROM test_task tt WHERE priority=1) tt
       //   INNER JOIN test t ON t.id=tt.pid
       // WHERE tt.task = 'code'
+      // @endcode
       $people = $select->execute()->fetchCol();
 
       $this->assertCount(1, $people, 'Returned the correct number of rows.');
@@ -61,9 +63,11 @@ public function testFromSubquerySelectWithLimit() {
     $select->addField('t', 'name');
 
     // The resulting query should be equivalent to:
+    // @code
     // SELECT t.name
     // FROM (SELECT tt.pid AS pid, tt.task AS task FROM test_task tt ORDER BY priority DESC LIMIT 1 OFFSET 0) tt
     //   INNER JOIN test t ON t.id=tt.pid
+    // @endcode
     $people = $select->execute()->fetchCol();
 
     $this->assertCount(1, $people, 'Returned the correct number of rows.');
@@ -170,11 +174,13 @@ public function testConditionSubquerySelect4() {
     $select->condition($subquery1, [$subquery2, $subquery3], 'BETWEEN');
 
     // The resulting query should be equivalent to:
+    // @code
     // SELECT t.name AS name
     // FROM {test} t
     // WHERE (SELECT AVG(tt.priority) AS expression FROM {test_task} tt WHERE (tt.pid = t.id))
     //   BETWEEN (SELECT MIN(tt2.priority) AS expression FROM {test_task} tt2 WHERE (tt2.pid <> t.id))
     //       AND (SELECT AVG(tt3.priority) AS expression FROM {test_task} tt3 WHERE (tt3.pid <> t.id));
+    // @endcode
     $people = $select->execute()->fetchCol();
     $this->assertEqualsCanonicalizing(['George', 'Paul'], $people, 'Returned George and Paul.');
   }
@@ -195,9 +201,11 @@ public function testJoinSubquerySelect() {
     $select->addField('t', 'name');
 
     // The resulting query should be equivalent to:
+    // @code
     // SELECT t.name
     // FROM test t
     //   INNER JOIN (SELECT tt.pid AS pid FROM test_task tt WHERE priority=1) tt ON t.id=tt.pid
+    // @endcode
     $people = $select->execute()->fetchCol();
 
     $this->assertCount(2, $people, 'Returned the correct number of rows.');
diff --git a/web/core/tests/Drupal/KernelTests/Core/Entity/EntityDefinitionUpdateTest.php b/web/core/tests/Drupal/KernelTests/Core/Entity/EntityDefinitionUpdateTest.php
index 516aa99510..9420cfa72d 100644
--- a/web/core/tests/Drupal/KernelTests/Core/Entity/EntityDefinitionUpdateTest.php
+++ b/web/core/tests/Drupal/KernelTests/Core/Entity/EntityDefinitionUpdateTest.php
@@ -582,7 +582,7 @@ public function testBaseFieldDeleteWithExistingData($entity_type_id, $create_ent
       ->orderBy('langcode', 'ASC')
       ->execute()
       ->fetchAll(\PDO::FETCH_ASSOC);
-    $this->assertCount(count($expected), $result);
+    $this->assertSameSize($expected, $result);
 
     // Use assertEquals and not assertSame here to prevent that a different
     // sequence of the columns in the table will affect the check.
@@ -622,7 +622,7 @@ public function testBaseFieldDeleteWithExistingData($entity_type_id, $create_ent
         ->orderBy('langcode', 'ASC')
         ->execute()
         ->fetchAll(\PDO::FETCH_ASSOC);
-      $this->assertCount(count($expected), $result);
+      $this->assertSameSize($expected, $result);
 
       // Use assertEquals and not assertSame here to prevent that a different
       // sequence of the columns in the table will affect the check.
diff --git a/web/core/tests/Drupal/KernelTests/Core/Entity/EntityDuplicateTest.php b/web/core/tests/Drupal/KernelTests/Core/Entity/EntityDuplicateTest.php
index c663ebd724..4480d4e1c6 100644
--- a/web/core/tests/Drupal/KernelTests/Core/Entity/EntityDuplicateTest.php
+++ b/web/core/tests/Drupal/KernelTests/Core/Entity/EntityDuplicateTest.php
@@ -41,7 +41,7 @@ public function testDuplicateNonDefaultRevision() {
 
     $duplicate_first_revision = $this->entityTestRevStorage->loadRevision($first_revision_id)->createDuplicate();
     $this->assertTrue($duplicate_first_revision->isDefaultRevision(), 'Duplicating a non-default revision creates a default revision.');
-    $this->assertEquals($duplicate_first_revision->label(), 'First Revision');
+    $this->assertEquals('First Revision', $duplicate_first_revision->label());
     $duplicate_first_revision->save();
 
     $duplicate_first_revision->name = 'Updated name';
diff --git a/web/core/tests/Drupal/KernelTests/Core/Entity/EntityHasFieldConstraintValidatorTest.php b/web/core/tests/Drupal/KernelTests/Core/Entity/EntityHasFieldConstraintValidatorTest.php
index ce60e6cdb8..fcccd1e3c2 100644
--- a/web/core/tests/Drupal/KernelTests/Core/Entity/EntityHasFieldConstraintValidatorTest.php
+++ b/web/core/tests/Drupal/KernelTests/Core/Entity/EntityHasFieldConstraintValidatorTest.php
@@ -47,7 +47,7 @@ public function testValidation() {
     // field has been created.
     $violations = $entity->validate();
     $this->assertCount(1, $violations);
-    $this->assertEquals($violations[0]->getMessage(), 'The entity must have the <em class="placeholder">body</em> field.');
+    $this->assertEquals('The entity must have the <em class="placeholder">body</em> field.', $violations[0]->getMessage());
     $storage->save($entity);
 
     // Create the field.
diff --git a/web/core/tests/Drupal/KernelTests/Core/Entity/EntityRevisionTranslationTest.php b/web/core/tests/Drupal/KernelTests/Core/Entity/EntityRevisionTranslationTest.php
index b2f0f17905..c67bb05482 100644
--- a/web/core/tests/Drupal/KernelTests/Core/Entity/EntityRevisionTranslationTest.php
+++ b/web/core/tests/Drupal/KernelTests/Core/Entity/EntityRevisionTranslationTest.php
@@ -134,8 +134,8 @@ public function testTranslationValuesWhenSavingPendingRevisions() {
 
     $pending_revision = $storage->loadRevision($pending_revision_id);
 
-    $this->assertEquals($pending_revision->name->value, 'updated pending revision - en');
-    $this->assertEquals($pending_revision->getTranslation('de')->name->value, 'pending revision - de');
+    $this->assertEquals('updated pending revision - en', $pending_revision->name->value);
+    $this->assertEquals('pending revision - de', $pending_revision->getTranslation('de')->name->value);
   }
 
   /**
diff --git a/web/core/tests/Drupal/KernelTests/Core/Installer/InstallerLanguageTest.php b/web/core/tests/Drupal/KernelTests/Core/Installer/InstallerLanguageTest.php
index 71f542839e..d2188d5884 100644
--- a/web/core/tests/Drupal/KernelTests/Core/Installer/InstallerLanguageTest.php
+++ b/web/core/tests/Drupal/KernelTests/Core/Installer/InstallerLanguageTest.php
@@ -32,7 +32,7 @@ public function testInstallerTranslationFiles() {
     $file_translation = new FileTranslation('core/tests/fixtures/files/translations', $this->container->get('file_system'));
     foreach ($expected_translation_files as $langcode => $files_expected) {
       $files_found = $file_translation->findTranslationFiles($langcode);
-      $this->assertSame(count($files_expected), count($files_found), new FormattableMarkup('@count installer languages found.', ['@count' => count($files_expected)]));
+      $this->assertSameSize($files_expected, $files_found, new FormattableMarkup('@count installer languages found.', ['@count' => count($files_expected)]));
       foreach ($files_found as $file) {
         $this->assertContains($file->filename, $files_expected, new FormattableMarkup('@file found.', ['@file' => $file->filename]));
       }
diff --git a/web/core/tests/Drupal/KernelTests/Core/Menu/MenuTreeStorageTest.php b/web/core/tests/Drupal/KernelTests/Core/Menu/MenuTreeStorageTest.php
index a504aaecdd..ea400d607a 100644
--- a/web/core/tests/Drupal/KernelTests/Core/Menu/MenuTreeStorageTest.php
+++ b/web/core/tests/Drupal/KernelTests/Core/Menu/MenuTreeStorageTest.php
@@ -432,7 +432,7 @@ protected function assertMenuLink($id, array $expected_properties, array $parent
     $query->condition('id', $parents, 'IN');
     $found_parents = $query->execute()->fetchAllKeyed(0, 1);
 
-    $this->assertSame(count($parents), count($found_parents), 'Found expected number of parents');
+    $this->assertSameSize($parents, $found_parents, 'Found expected number of parents');
     $this->assertCount($raw['depth'], $found_parents, 'Number of parents is the same as the depth');
 
     $materialized_path = $this->treeStorage->getRootPathIds($id);
diff --git a/web/core/tests/Drupal/KernelTests/Core/Routing/RouteProviderTest.php b/web/core/tests/Drupal/KernelTests/Core/Routing/RouteProviderTest.php
index fac83cd2b8..350e400a68 100644
--- a/web/core/tests/Drupal/KernelTests/Core/Routing/RouteProviderTest.php
+++ b/web/core/tests/Drupal/KernelTests/Core/Routing/RouteProviderTest.php
@@ -307,12 +307,11 @@ public function testGetAllRoutes() {
     $dumper->dump();
 
     $sample_routes = $this->fixtures->staticSampleRouteCollection();
-    $expected_route_count = count($sample_routes);
 
     $returned_routes = $provider->getAllRoutes();
 
     $this->assertInstanceOf(\Iterator::class, $returned_routes);
-    $this->assertEquals($expected_route_count, count($returned_routes));
+    $this->assertSameSize($sample_routes, $returned_routes);
 
     foreach ($returned_routes as $route_name => $route) {
       $this->assertArrayHasKey($route_name, $sample_routes);
diff --git a/web/core/tests/Drupal/KernelTests/KernelTestBase.php b/web/core/tests/Drupal/KernelTests/KernelTestBase.php
index 780c9059e0..3cc63bcc1f 100644
--- a/web/core/tests/Drupal/KernelTests/KernelTestBase.php
+++ b/web/core/tests/Drupal/KernelTests/KernelTestBase.php
@@ -484,7 +484,7 @@ protected function initFileCache() {
     // Provide a default configuration, if not set.
     if (!isset($configuration['default'])) {
       // @todo Use extension_loaded('apcu') for non-testbot
-      //  https://www.drupal.org/node/2447753.
+      //   https://www.drupal.org/node/2447753.
       if (function_exists('apcu_fetch')) {
         $configuration['default']['cache_backend_class'] = ApcuFileCacheBackend::class;
       }
diff --git a/web/core/tests/Drupal/Tests/Component/Annotation/Doctrine/DocParserTest.php b/web/core/tests/Drupal/Tests/Component/Annotation/Doctrine/DocParserTest.php
index ad2cd7b906..5a028bcb4f 100644
--- a/web/core/tests/Drupal/Tests/Component/Annotation/Doctrine/DocParserTest.php
+++ b/web/core/tests/Drupal/Tests/Component/Annotation/Doctrine/DocParserTest.php
@@ -211,7 +211,7 @@ public function testAnnotationWithoutConstructor()
 
         $this->assertNull($annot->name);
         $this->assertNotNull($annot->data);
-        $this->assertEquals($annot->data, "Some data");
+        $this->assertEquals("Some data", $annot->data);
 
 
 
@@ -230,8 +230,8 @@ public function testAnnotationWithoutConstructor()
         $this->assertNotNull($annot);
         $this->assertInstanceOf(SomeAnnotationClassNameWithoutConstructor::class, $annot);
 
-        $this->assertEquals($annot->name, "Some Name");
-        $this->assertEquals($annot->data, "Some data");
+        $this->assertEquals("Some Name", $annot->name);
+        $this->assertEquals("Some data", $annot->data);
 
 
 
@@ -246,7 +246,7 @@ public function testAnnotationWithoutConstructor()
         $this->assertCount(1, $result);
         $annot      = $result[0];
 
-        $this->assertEquals($annot->data, "Some data");
+        $this->assertEquals("Some data", $annot->data);
         $this->assertNull($annot->name);
 
 
@@ -260,7 +260,7 @@ public function testAnnotationWithoutConstructor()
         $this->assertCount(1, $result);
         $annot      = $result[0];
 
-        $this->assertEquals($annot->name, "Some name");
+        $this->assertEquals("Some name", $annot->name);
         $this->assertNull($annot->data);
 
         $docblock = <<<DOCBLOCK
@@ -273,7 +273,7 @@ public function testAnnotationWithoutConstructor()
         $this->assertCount(1, $result);
         $annot      = $result[0];
 
-        $this->assertEquals($annot->data, "Some data");
+        $this->assertEquals("Some data", $annot->data);
         $this->assertNull($annot->name);
 
 
@@ -288,8 +288,8 @@ public function testAnnotationWithoutConstructor()
         $this->assertCount(1, $result);
         $annot      = $result[0];
 
-        $this->assertEquals($annot->name, "Some name");
-        $this->assertEquals($annot->data, "Some data");
+        $this->assertEquals("Some name", $annot->name);
+        $this->assertEquals("Some data", $annot->data);
 
 
         $docblock = <<<DOCBLOCK
@@ -302,8 +302,8 @@ public function testAnnotationWithoutConstructor()
         $this->assertCount(1, $result);
         $annot      = $result[0];
 
-        $this->assertEquals($annot->name, "Some name");
-        $this->assertEquals($annot->data, "Some data");
+        $this->assertEquals("Some name", $annot->name);
+        $this->assertEquals("Some data", $annot->data);
 
         $docblock = <<<DOCBLOCK
 /**
diff --git a/web/core/tests/Drupal/Tests/Component/DependencyInjection/ContainerTest.php b/web/core/tests/Drupal/Tests/Component/DependencyInjection/ContainerTest.php
index 4818274884..eeb933e0d0 100644
--- a/web/core/tests/Drupal/Tests/Component/DependencyInjection/ContainerTest.php
+++ b/web/core/tests/Drupal/Tests/Component/DependencyInjection/ContainerTest.php
@@ -168,7 +168,7 @@ public function testGet() {
     $this->assertEquals($some_parameter, $service->getSomeParameter(), '%some_config% was injected via constructor.');
     $this->assertEquals($this->container, $service->getContainer(), 'Container was injected via setter injection.');
     $this->assertEquals($some_other_parameter, $service->getSomeOtherParameter(), '%some_other_config% was injected via setter injection.');
-    $this->assertEquals($service->_someProperty, 'foo', 'Service has added properties.');
+    $this->assertEquals('foo', $service->_someProperty, 'Service has added properties.');
   }
 
   /**
@@ -540,13 +540,13 @@ public function testGetForConfigurator() {
   public function testResolveServicesAndParametersForPrivateService() {
     $service = $this->container->get('service_using_private');
     $private_service = $service->getSomeOtherService();
-    $this->assertEquals($private_service->getSomeParameter(), 'really_private_lama', 'Private was found successfully.');
+    $this->assertEquals('really_private_lama', $private_service->getSomeParameter(), 'Private was found successfully.');
 
     // Test that sharing the same private services works.
     $service = $this->container->get('another_service_using_private');
     $another_private_service = $service->getSomeOtherService();
     $this->assertNotSame($private_service, $another_private_service, 'Private service is not shared.');
-    $this->assertEquals($private_service->getSomeParameter(), 'really_private_lama', 'Private was found successfully.');
+    $this->assertEquals('really_private_lama', $private_service->getSomeParameter(), 'Private was found successfully.');
   }
 
   /**
@@ -559,13 +559,13 @@ public function testResolveServicesAndParametersForPrivateService() {
   public function testResolveServicesAndParametersForSharedPrivateService() {
     $service = $this->container->get('service_using_shared_private');
     $private_service = $service->getSomeOtherService();
-    $this->assertEquals($private_service->getSomeParameter(), 'really_private_lama', 'Private was found successfully.');
+    $this->assertEquals('really_private_lama', $private_service->getSomeParameter(), 'Private was found successfully.');
 
     // Test that sharing the same private services works.
     $service = $this->container->get('another_service_using_shared_private');
     $same_private_service = $service->getSomeOtherService();
     $this->assertSame($private_service, $same_private_service, 'Private service is shared.');
-    $this->assertEquals($private_service->getSomeParameter(), 'really_private_lama', 'Private was found successfully.');
+    $this->assertEquals('really_private_lama', $private_service->getSomeParameter(), 'Private was found successfully.');
   }
 
   /**
diff --git a/web/core/tests/Drupal/Tests/Component/Diff/Engine/DiffEngineTest.php b/web/core/tests/Drupal/Tests/Component/Diff/Engine/DiffEngineTest.php
index 1714e663be..895faebeb5 100644
--- a/web/core/tests/Drupal/Tests/Component/Diff/Engine/DiffEngineTest.php
+++ b/web/core/tests/Drupal/Tests/Component/Diff/Engine/DiffEngineTest.php
@@ -79,7 +79,7 @@ public function testDiff($expected, $from, $to) {
     $diff_engine = new DiffEngine();
     $diff = $diff_engine->diff($from, $to);
     // Make sure we have the same number of results as expected.
-    $this->assertCount(count($expected), $diff);
+    $this->assertSameSize($expected, $diff);
     // Make sure the diff objects match our expectations.
     foreach ($expected as $index => $op_class) {
       $this->assertEquals($op_class, get_class($diff[$index]));
diff --git a/web/core/tests/Drupal/Tests/Component/Discovery/YamlDiscoveryTest.php b/web/core/tests/Drupal/Tests/Component/Discovery/YamlDiscoveryTest.php
index 6202f3f4fe..8f5d01ec6f 100644
--- a/web/core/tests/Drupal/Tests/Component/Discovery/YamlDiscoveryTest.php
+++ b/web/core/tests/Drupal/Tests/Component/Discovery/YamlDiscoveryTest.php
@@ -62,7 +62,7 @@ public function testDiscovery() {
 
     foreach (['test_1', 'test_2', 'test_3'] as $key) {
       $this->assertArrayHasKey('name', $data[$key]);
-      $this->assertEquals($data[$key]['name'], 'test');
+      $this->assertEquals('test', $data[$key]['name']);
     }
 
     $this->assertSame([], $data['test_4']);
diff --git a/web/core/tests/Drupal/Tests/Component/Graph/GraphTest.php b/web/core/tests/Drupal/Tests/Component/Graph/GraphTest.php
index 0d64cbf024..9448e6cdc1 100644
--- a/web/core/tests/Drupal/Tests/Component/Graph/GraphTest.php
+++ b/web/core/tests/Drupal/Tests/Component/Graph/GraphTest.php
@@ -16,11 +16,13 @@ class GraphTest extends TestCase {
    */
   public function testDepthFirstSearch() {
     // The sample graph used is:
+    // @code
     // 1 --> 2 --> 3     5 ---> 6
     //       |     ^     ^
     //       |     |     |
     //       |     |     |
     //       +---> 4 <-- 7      8 ---> 9
+    // @endcode
     $graph = $this->normalizeGraph([
       1 => [2],
       2 => [3, 4],
diff --git a/web/core/tests/Drupal/Tests/Component/Utility/XssTest.php b/web/core/tests/Drupal/Tests/Component/Utility/XssTest.php
index 31b31f6f08..b0c434da5d 100644
--- a/web/core/tests/Drupal/Tests/Component/Utility/XssTest.php
+++ b/web/core/tests/Drupal/Tests/Component/Utility/XssTest.php
@@ -431,7 +431,7 @@ public function providerTestFilterXssNotNormalized() {
         ['p'],
       ],
     ];
-    // @fixme This dataset currently fails under 5.4 because of
+    // @todo This dataset currently fails under 5.4 because of
     //   https://www.drupal.org/node/1210798. Restore after its fixed.
     if (version_compare(PHP_VERSION, '5.4.0', '<')) {
       $cases[] = [
@@ -541,7 +541,7 @@ public function providerTestAttributes() {
    */
   public function testFilterXSSAdmin() {
     $value = Xss::filterAdmin('<style /><iframe /><frame /><frameset /><meta /><link /><embed /><applet /><param /><layer />');
-    $this->assertEquals($value, '', 'Admin HTML filter -- should never allow some tags.');
+    $this->assertEquals('', $value, 'Admin HTML filter -- should never allow some tags.');
   }
 
   /**
diff --git a/web/core/tests/Drupal/Tests/Core/Access/AccessManagerTest.php b/web/core/tests/Drupal/Tests/Core/Access/AccessManagerTest.php
index 167a62fc29..264b2bde3b 100644
--- a/web/core/tests/Drupal/Tests/Core/Access/AccessManagerTest.php
+++ b/web/core/tests/Drupal/Tests/Core/Access/AccessManagerTest.php
@@ -147,9 +147,9 @@ public function testSetChecks() {
 
     $this->checkProvider->setChecks($this->routeCollection);
 
-    $this->assertEquals($this->routeCollection->get('test_route_1')->getOption('_access_checks'), NULL);
-    $this->assertEquals($this->routeCollection->get('test_route_2')->getOption('_access_checks'), ['test_access_default']);
-    $this->assertEquals($this->routeCollection->get('test_route_3')->getOption('_access_checks'), ['test_access_default']);
+    $this->assertNull($this->routeCollection->get('test_route_1')->getOption('_access_checks'));
+    $this->assertEquals(['test_access_default'], $this->routeCollection->get('test_route_2')->getOption('_access_checks'));
+    $this->assertEquals(['test_access_default'], $this->routeCollection->get('test_route_3')->getOption('_access_checks'));
   }
 
   /**
@@ -333,23 +333,12 @@ public function testCheckNamedRoute() {
     $this->checkProvider->setChecks($this->routeCollection);
     $this->setupAccessArgumentsResolverFactory();
 
-    $this->paramConverter->expects($this->at(0))
+    $this->paramConverter->expects($this->exactly(4))
       ->method('convert')
-      ->with([RouteObjectInterface::ROUTE_NAME => 'test_route_2', RouteObjectInterface::ROUTE_OBJECT => $this->routeCollection->get('test_route_2')])
-      ->will($this->returnValue([]));
-    $this->paramConverter->expects($this->at(1))
-      ->method('convert')
-      ->with([RouteObjectInterface::ROUTE_NAME => 'test_route_2', RouteObjectInterface::ROUTE_OBJECT => $this->routeCollection->get('test_route_2')])
-      ->will($this->returnValue([]));
-
-    $this->paramConverter->expects($this->at(2))
-      ->method('convert')
-      ->with(['value' => 'example', RouteObjectInterface::ROUTE_NAME => 'test_route_4', RouteObjectInterface::ROUTE_OBJECT => $this->routeCollection->get('test_route_4')])
-      ->will($this->returnValue(['value' => 'example']));
-    $this->paramConverter->expects($this->at(3))
-      ->method('convert')
-      ->with(['value' => 'example', RouteObjectInterface::ROUTE_NAME => 'test_route_4', RouteObjectInterface::ROUTE_OBJECT => $this->routeCollection->get('test_route_4')])
-      ->will($this->returnValue(['value' => 'example']));
+      ->willReturnMap([
+        [[RouteObjectInterface::ROUTE_NAME => 'test_route_2', RouteObjectInterface::ROUTE_OBJECT => $this->routeCollection->get('test_route_2')], []],
+        [['value' => 'example', RouteObjectInterface::ROUTE_NAME => 'test_route_4', RouteObjectInterface::ROUTE_OBJECT => $this->routeCollection->get('test_route_4')], ['value' => 'example']],
+      ]);
 
     // Tests the access with routes with parameters without given request.
     $this->assertEquals(TRUE, $this->accessManager->checkNamedRoute('test_route_2', [], $this->account));
diff --git a/web/core/tests/Drupal/Tests/Core/Access/CustomAccessCheckTest.php b/web/core/tests/Drupal/Tests/Core/Access/CustomAccessCheckTest.php
index d5be432e5b..33509635e6 100644
--- a/web/core/tests/Drupal/Tests/Core/Access/CustomAccessCheckTest.php
+++ b/web/core/tests/Drupal/Tests/Core/Access/CustomAccessCheckTest.php
@@ -61,44 +61,34 @@ protected function setUp(): void {
   public function testAccess() {
     $route_match = $this->createMock('Drupal\Core\Routing\RouteMatchInterface');
 
-    $this->controllerResolver->expects($this->at(0))
+    $this->controllerResolver->expects($this->exactly(3))
       ->method('getControllerFromDefinition')
-      ->with('\Drupal\Tests\Core\Access\TestController::accessDeny')
-      ->will($this->returnValue([new TestController(), 'accessDeny']));
+      ->willReturnMap([
+        ['\Drupal\Tests\Core\Access\TestController::accessDeny', [new TestController(), 'accessDeny']],
+        ['\Drupal\Tests\Core\Access\TestController::accessAllow', [new TestController(), 'accessAllow']],
+        ['\Drupal\Tests\Core\Access\TestController::accessParameter', [new TestController(), 'accessParameter']],
+      ]);
 
     $resolver0 = $this->createMock('Drupal\Component\Utility\ArgumentsResolverInterface');
     $resolver0->expects($this->once())
       ->method('getArguments')
       ->will($this->returnValue([]));
-    $this->argumentsResolverFactory->expects($this->at(0))
-      ->method('getArgumentsResolver')
-      ->will($this->returnValue($resolver0));
-
-    $this->controllerResolver->expects($this->at(1))
-      ->method('getControllerFromDefinition')
-      ->with('\Drupal\Tests\Core\Access\TestController::accessAllow')
-      ->will($this->returnValue([new TestController(), 'accessAllow']));
-
     $resolver1 = $this->createMock('Drupal\Component\Utility\ArgumentsResolverInterface');
     $resolver1->expects($this->once())
       ->method('getArguments')
       ->will($this->returnValue([]));
-    $this->argumentsResolverFactory->expects($this->at(1))
-      ->method('getArgumentsResolver')
-      ->will($this->returnValue($resolver1));
-
-    $this->controllerResolver->expects($this->at(2))
-      ->method('getControllerFromDefinition')
-      ->with('\Drupal\Tests\Core\Access\TestController::accessParameter')
-      ->will($this->returnValue([new TestController(), 'accessParameter']));
-
     $resolver2 = $this->createMock('Drupal\Component\Utility\ArgumentsResolverInterface');
     $resolver2->expects($this->once())
       ->method('getArguments')
       ->will($this->returnValue(['parameter' => 'TRUE']));
-    $this->argumentsResolverFactory->expects($this->at(2))
+
+    $this->argumentsResolverFactory->expects($this->exactly(3))
       ->method('getArgumentsResolver')
-      ->will($this->returnValue($resolver2));
+      ->willReturnOnConsecutiveCalls(
+        $resolver0,
+        $resolver1,
+        $resolver2,
+      );
 
     $route = new Route('/test-route', [], ['_custom_access' => '\Drupal\Tests\Core\Access\TestController::accessDeny']);
     $account = $this->createMock('Drupal\Core\Session\AccountInterface');
diff --git a/web/core/tests/Drupal/Tests/Core/Ajax/AjaxResponseTest.php b/web/core/tests/Drupal/Tests/Core/Ajax/AjaxResponseTest.php
index 18cb2a6454..2e2b93532b 100644
--- a/web/core/tests/Drupal/Tests/Core/Ajax/AjaxResponseTest.php
+++ b/web/core/tests/Drupal/Tests/Core/Ajax/AjaxResponseTest.php
@@ -88,7 +88,7 @@ public function testPrepareResponseForIeFormRequestsWithFileUpload() {
     );
     $subscriber->onResponse($event);
     $this->assertEquals('text/html; charset=utf-8', $response->headers->get('Content-Type'));
-    $this->assertEquals($response->getContent(), '<textarea>[]</textarea>');
+    $this->assertEquals('<textarea>[]</textarea>', $response->getContent());
   }
 
 }
diff --git a/web/core/tests/Drupal/Tests/Core/Asset/LibraryDiscoveryCollectorTest.php b/web/core/tests/Drupal/Tests/Core/Asset/LibraryDiscoveryCollectorTest.php
index f83b1499f0..b2d3698465 100644
--- a/web/core/tests/Drupal/Tests/Core/Asset/LibraryDiscoveryCollectorTest.php
+++ b/web/core/tests/Drupal/Tests/Core/Asset/LibraryDiscoveryCollectorTest.php
@@ -189,18 +189,18 @@ public function testLibrariesExtend() {
           'kitten_theme/extend',
         ],
       ]);
-    $this->libraryDiscoveryParser->expects($this->at(0))
+    $this->libraryDiscoveryParser->expects($this->exactly(2))
       ->method('buildByExtension')
-      ->with('test')
-      ->willReturn($this->libraryData);
-    $this->libraryDiscoveryParser->expects($this->at(1))
-      ->method('buildByExtension')
-      ->with('kitten_theme')
-      ->willReturn([
-        'extend' => [
-          'css' => [
-            'theme' => [
-              'baz.css' => [],
+      ->willReturnMap([
+        ['test', $this->libraryData],
+        [
+          'kitten_theme', [
+            'extend' => [
+              'css' => [
+                'theme' => [
+                  'baz.css' => [],
+                ],
+              ],
             ],
           ],
         ],
@@ -235,18 +235,18 @@ public function testLibrariesExtendDeprecated() {
           'kitten_theme/extend',
         ],
       ]);
-    $this->libraryDiscoveryParser->expects($this->at(0))
+    $this->libraryDiscoveryParser->expects($this->exactly(2))
       ->method('buildByExtension')
-      ->with('test')
-      ->willReturn($this->libraryData);
-    $this->libraryDiscoveryParser->expects($this->at(1))
-      ->method('buildByExtension')
-      ->with('kitten_theme')
-      ->willReturn([
-        'extend' => [
-          'css' => [
-            'theme' => [
-              'baz.css' => [],
+      ->willReturnMap([
+        ['test', $this->libraryData],
+        [
+          'kitten_theme', [
+            'extend' => [
+              'css' => [
+                'theme' => [
+                  'baz.css' => [],
+                ],
+              ],
             ],
           ],
         ],
diff --git a/web/core/tests/Drupal/Tests/Core/Cache/CacheCollectorTest.php b/web/core/tests/Drupal/Tests/Core/Cache/CacheCollectorTest.php
index f83e4612b7..2c7c041a6d 100644
--- a/web/core/tests/Drupal/Tests/Core/Cache/CacheCollectorTest.php
+++ b/web/core/tests/Drupal/Tests/Core/Cache/CacheCollectorTest.php
@@ -219,35 +219,32 @@ public function testUpdateCacheInvalidatedConflict() {
     $key = $this->randomMachineName();
     $value = $this->randomMachineName();
 
-    $cache = (object) [
-      'data' => [$key => $value],
-      'created' => (int) $_SERVER['REQUEST_TIME'],
-    ];
-    $this->cacheBackend->expects($this->at(0))
+    // Set up mock cache get with conflicting entries.
+    $this->cacheBackend->expects($this->exactly(2))
       ->method('get')
       ->with($this->cid)
-      ->will($this->returnValue($cache));
+      ->willReturnOnConsecutiveCalls(
+        (object) [
+          'data' => [$key => $value],
+          'created' => (int) $_SERVER['REQUEST_TIME'],
+        ],
+        (object) [
+          'data' => [$key => $value],
+          'created' => (int) $_SERVER['REQUEST_TIME'] + 1,
+        ],
+      );
 
-    $this->cacheBackend->expects($this->at(1))
+    $this->cacheBackend->expects($this->once())
       ->method('invalidate')
       ->with($this->cid);
     $this->collector->set($key, 'new value');
 
     // Set up mock objects for the expected calls, first a lock acquire, then
-    // cache get to look for conflicting cache entries, which does find
-    // and then it deletes the cache and aborts.
+    // when cache get finds conflicting entries it deletes the cache and aborts.
     $this->lock->expects($this->once())
       ->method('acquire')
       ->with($this->cid . ':Drupal\Core\Cache\CacheCollector')
       ->will($this->returnValue(TRUE));
-    $cache = (object) [
-      'data' => [$key => $value],
-      'created' => (int) $_SERVER['REQUEST_TIME'] + 1,
-    ];
-    $this->cacheBackend->expects($this->at(0))
-      ->method('get')
-      ->with($this->cid)
-      ->will($this->returnValue($cache));
     $this->cacheBackend->expects($this->once())
       ->method('delete')
       ->with($this->cid);
@@ -280,7 +277,7 @@ public function testUpdateCacheMerge() {
       'data' => ['other key' => 'other value'],
       'created' => (int) $_SERVER['REQUEST_TIME'] + 1,
     ];
-    $this->cacheBackend->expects($this->at(0))
+    $this->cacheBackend->expects($this->once())
       ->method('get')
       ->with($this->cid)
       ->will($this->returnValue($cache));
@@ -306,26 +303,24 @@ public function testUpdateCacheDelete() {
       'data' => [$key => $value],
       'created' => (int) $_SERVER['REQUEST_TIME'],
     ];
-    $this->cacheBackend->expects($this->at(0))
+    // Set up mock expectation, on the second call the with the second argument
+    // set to TRUE because we triggered a cache invalidation.
+    $this->cacheBackend->expects($this->exactly(2))
       ->method('get')
-      ->with($this->cid)
+      ->withConsecutive(
+        [$this->cid],
+        [$this->cid, TRUE],
+      )
       ->will($this->returnValue($cache));
 
     $this->collector->delete($key);
 
     // Set up mock objects for the expected calls, first a lock acquire, then
-    // cache get to look for conflicting cache entries, then a cache set and
-    // finally the lock is released again.
+    // a cache set and finally the lock is released again.
     $this->lock->expects($this->once())
       ->method('acquire')
       ->with($this->cid . ':Drupal\Core\Cache\CacheCollector')
       ->will($this->returnValue(TRUE));
-    // The second argument is set to TRUE because we triggered a cache
-    // invalidation.
-    $this->cacheBackend->expects($this->at(0))
-      ->method('get')
-      ->with($this->cid, TRUE)
-      ->will($this->returnValue($cache));
     $this->cacheBackend->expects($this->once())
       ->method('set')
       ->with($this->cid, [], Cache::PERMANENT, []);
diff --git a/web/core/tests/Drupal/Tests/Core/Cache/Context/SessionCacheContextTest.php b/web/core/tests/Drupal/Tests/Core/Cache/Context/SessionCacheContextTest.php
index a86e8a3233..b68332e34d 100644
--- a/web/core/tests/Drupal/Tests/Core/Cache/Context/SessionCacheContextTest.php
+++ b/web/core/tests/Drupal/Tests/Core/Cache/Context/SessionCacheContextTest.php
@@ -70,14 +70,10 @@ public function testDifferentContextForDifferentSession() {
     $cache_context = new SessionCacheContext($this->requestStack);
 
     $session1_id = 'pjH_8aSoofyCDQiuVYXJcbfyr-CPtkUY';
-    $this->session->expects($this->at(0))
-      ->method('getId')
-      ->will($this->returnValue($session1_id));
-
     $session2_id = 'aSebeZ52bbM6SvADurQP89SFnEpxY6j8';
-    $this->session->expects($this->at(1))
+    $this->session->expects($this->exactly(2))
       ->method('getId')
-      ->will($this->returnValue($session2_id));
+      ->willReturnOnConsecutiveCalls($session1_id, $session2_id);
 
     $context1 = $cache_context->getContext();
     $context2 = $cache_context->getContext();
diff --git a/web/core/tests/Drupal/Tests/Core/Config/Entity/ConfigEntityBaseUnitTest.php b/web/core/tests/Drupal/Tests/Core/Config/Entity/ConfigEntityBaseUnitTest.php
index ffca4262b8..07c07d01d9 100644
--- a/web/core/tests/Drupal/Tests/Core/Config/Entity/ConfigEntityBaseUnitTest.php
+++ b/web/core/tests/Drupal/Tests/Core/Config/Entity/ConfigEntityBaseUnitTest.php
@@ -476,21 +476,18 @@ public function testIsSyncing() {
    * @covers ::createDuplicate
    */
   public function testCreateDuplicate() {
-    $this->entityType->expects($this->at(0))
+    $this->entityType->expects($this->exactly(2))
       ->method('getKey')
-      ->with('id')
-      ->will($this->returnValue('id'));
+      ->willReturnMap([
+        ['id', 'id'],
+        ['uuid', 'uuid'],
+      ]);
 
-    $this->entityType->expects($this->at(1))
+    $this->entityType->expects($this->once())
       ->method('hasKey')
       ->with('uuid')
       ->will($this->returnValue(TRUE));
 
-    $this->entityType->expects($this->at(2))
-      ->method('getKey')
-      ->with('uuid')
-      ->will($this->returnValue('uuid'));
-
     $new_uuid = '8607ef21-42bc-4913-978f-8c06207b0395';
     $this->uuid->expects($this->once())
       ->method('generate')
diff --git a/web/core/tests/Drupal/Tests/Core/Config/Entity/EntityDisplayModeBaseUnitTest.php b/web/core/tests/Drupal/Tests/Core/Config/Entity/EntityDisplayModeBaseUnitTest.php
index 1b01071b16..aa621dfb52 100644
--- a/web/core/tests/Drupal/Tests/Core/Config/Entity/EntityDisplayModeBaseUnitTest.php
+++ b/web/core/tests/Drupal/Tests/Core/Config/Entity/EntityDisplayModeBaseUnitTest.php
@@ -81,14 +81,12 @@ public function testCalculateDependencies() {
       ->will($this->returnValue('test_module'));
     $values = ['targetEntityType' => $target_entity_type_id];
 
-    $this->entityTypeManager->expects($this->at(0))
+    $this->entityTypeManager->expects($this->exactly(2))
       ->method('getDefinition')
-      ->with($target_entity_type_id)
-      ->will($this->returnValue($target_entity_type));
-    $this->entityTypeManager->expects($this->at(1))
-      ->method('getDefinition')
-      ->with($this->entityType)
-      ->will($this->returnValue($this->entityInfo));
+      ->willReturnMap([
+        [$target_entity_type_id, TRUE, $target_entity_type],
+        [$this->entityType, TRUE, $this->entityInfo],
+      ]);
 
     $this->entity = $this->getMockBuilder('\Drupal\Core\Entity\EntityDisplayModeBase')
       ->setConstructorArgs([$values, $this->entityType])
diff --git a/web/core/tests/Drupal/Tests/Core/Database/Driver/pgsql/PostgresqlSchemaTest.php b/web/core/tests/Drupal/Tests/Core/Database/Driver/pgsql/PostgresqlSchemaTest.php
index 48c835da08..df2a05f116 100644
--- a/web/core/tests/Drupal/Tests/Core/Database/Driver/pgsql/PostgresqlSchemaTest.php
+++ b/web/core/tests/Drupal/Tests/Core/Database/Driver/pgsql/PostgresqlSchemaTest.php
@@ -53,14 +53,16 @@ public function testComputedConstraintName($table_name, $name, $expected) {
       ->method('fetchField')
       ->willReturn($max_identifier_length);
 
-    $this->connection->expects($this->any())
+    $this->connection->expects($this->exactly(2))
       ->method('query')
-      ->willReturn($statement);
-
-    $this->connection->expects($this->at(2))
-      ->method('query')
-      ->with("SELECT 1 FROM pg_constraint WHERE conname = '$expected'")
-      ->willReturn($this->createMock('\Drupal\Core\Database\StatementInterface'));
+      ->withConsecutive(
+        [$this->anything()],
+        ["SELECT 1 FROM pg_constraint WHERE conname = '$expected'"],
+      )
+      ->willReturnOnConsecutiveCalls(
+        $statement,
+        $this->createMock('\Drupal\Core\Database\StatementInterface'),
+      );
 
     $schema->constraintExists($table_name, $name);
   }
diff --git a/web/core/tests/Drupal/Tests/Core/Database/EmptyStatementTest.php b/web/core/tests/Drupal/Tests/Core/Database/EmptyStatementTest.php
index 93982c66e7..f17c968ab9 100644
--- a/web/core/tests/Drupal/Tests/Core/Database/EmptyStatementTest.php
+++ b/web/core/tests/Drupal/Tests/Core/Database/EmptyStatementTest.php
@@ -40,7 +40,7 @@ public function testEmptyIteration() {
   public function testEmptyFetchAll() {
     $result = new StatementEmpty();
 
-    $this->assertEquals($result->fetchAll(), [], 'Empty array returned from empty result set.');
+    $this->assertEquals([], $result->fetchAll(), 'Empty array returned from empty result set.');
   }
 
 }
diff --git a/web/core/tests/Drupal/Tests/Core/Database/OrderByTest.php b/web/core/tests/Drupal/Tests/Core/Database/OrderByTest.php
index 8f7427ed3e..0e793429b1 100644
--- a/web/core/tests/Drupal/Tests/Core/Database/OrderByTest.php
+++ b/web/core/tests/Drupal/Tests/Core/Database/OrderByTest.php
@@ -36,7 +36,7 @@ protected function setUp(): void {
   public function testInvalidDirection() {
     $this->query->orderBy('test', 'invalid direction');
     $order_bys = $this->query->getOrderBy();
-    $this->assertEquals($order_bys['test'], 'ASC', 'Invalid order by direction is converted to ASC.');
+    $this->assertEquals('ASC', $order_bys['test'], 'Invalid order by direction is converted to ASC.');
   }
 
   /**
diff --git a/web/core/tests/Drupal/Tests/Core/Datetime/DateTest.php b/web/core/tests/Drupal/Tests/Core/Datetime/DateTest.php
index 09c938f3b1..735c1fe8a9 100644
--- a/web/core/tests/Drupal/Tests/Core/Datetime/DateTest.php
+++ b/web/core/tests/Drupal/Tests/Core/Datetime/DateTest.php
@@ -185,16 +185,12 @@ public function testFormatTimeDiffUntil() {
 
     // Mocks the formatDiff function of the dateformatter object.
     $this->dateFormatterStub
-      ->expects($this->at(0))
+      ->expects($this->exactly(2))
       ->method('formatDiff')
-      ->with($timestamp, $request_time, $options)
-      ->will($this->returnValue($expected));
-
-    $this->dateFormatterStub
-      ->expects($this->at(1))
-      ->method('formatDiff')
-      ->with($timestamp, $request_time, $options + ['return_as_object' => TRUE])
-      ->will($this->returnValue(new FormattedDateDiff('1 second', 1)));
+      ->willReturnMap([
+        [$timestamp, $request_time, $options, $expected],
+        [$timestamp, $request_time, $options + ['return_as_object' => TRUE], new FormattedDateDiff('1 second', 1)],
+      ]);
 
     $request = Request::createFromGlobals();
     $request->server->set('REQUEST_TIME', $request_time);
@@ -222,16 +218,12 @@ public function testFormatTimeDiffSince() {
 
     // Mocks the formatDiff function of the dateformatter object.
     $this->dateFormatterStub
-      ->expects($this->at(0))
-      ->method('formatDiff')
-      ->with($request_time, $timestamp, $options)
-      ->will($this->returnValue($expected));
-
-    $this->dateFormatterStub
-      ->expects($this->at(1))
+      ->expects($this->exactly(2))
       ->method('formatDiff')
-      ->with($request_time, $timestamp, $options + ['return_as_object' => TRUE])
-      ->will($this->returnValue(new FormattedDateDiff('1 second', 1)));
+      ->willReturnMap([
+        [$request_time, $timestamp, $options, $expected],
+        [$request_time, $timestamp, $options + ['return_as_object' => TRUE], new FormattedDateDiff('1 second', 1)],
+      ]);
 
     $request = Request::createFromGlobals();
     $request->server->set('REQUEST_TIME', $request_time);
diff --git a/web/core/tests/Drupal/Tests/Core/Entity/ContentEntityBaseUnitTest.php b/web/core/tests/Drupal/Tests/Core/Entity/ContentEntityBaseUnitTest.php
index f984ab1173..05207266c8 100644
--- a/web/core/tests/Drupal/Tests/Core/Entity/ContentEntityBaseUnitTest.php
+++ b/web/core/tests/Drupal/Tests/Core/Entity/ContentEntityBaseUnitTest.php
@@ -220,27 +220,11 @@ protected function setUp(): void {
   public function testIsNewRevision() {
     // Set up the entity type so that on the first call there is no revision key
     // and on the second call there is one.
-    $this->entityType->expects($this->at(0))
+    $this->entityType->expects($this->exactly(4))
       ->method('hasKey')
       ->with('revision')
-      ->will($this->returnValue(FALSE));
-    $this->entityType->expects($this->at(1))
-      ->method('hasKey')
-      ->with('revision')
-      ->will($this->returnValue(TRUE));
-    $this->entityType->expects($this->at(2))
-      ->method('hasKey')
-      ->with('revision')
-      ->will($this->returnValue(TRUE));
-    $this->entityType->expects($this->at(3))
-      ->method('getKey')
-      ->with('revision')
-      ->will($this->returnValue('revision_id'));
-    $this->entityType->expects($this->at(4))
-      ->method('hasKey')
-      ->with('revision')
-      ->will($this->returnValue(TRUE));
-    $this->entityType->expects($this->at(5))
+      ->willReturnOnConsecutiveCalls(FALSE, TRUE, TRUE, TRUE);
+    $this->entityType->expects($this->exactly(2))
       ->method('getKey')
       ->with('revision')
       ->will($this->returnValue('revision_id'));
@@ -361,14 +345,10 @@ public function testValidate() {
     $non_empty_violation_list = clone $empty_violation_list;
     $violation = $this->createMock('\Symfony\Component\Validator\ConstraintViolationInterface');
     $non_empty_violation_list->add($violation);
-    $validator->expects($this->at(0))
-      ->method('validate')
-      ->with($this->entity->getTypedData())
-      ->will($this->returnValue($empty_violation_list));
-    $validator->expects($this->at(1))
+    $validator->expects($this->exactly(2))
       ->method('validate')
       ->with($this->entity->getTypedData())
-      ->will($this->returnValue($non_empty_violation_list));
+      ->willReturnOnConsecutiveCalls($empty_violation_list, $non_empty_violation_list);
     $this->typedDataManager->expects($this->exactly(2))
       ->method('getValidator')
       ->will($this->returnValue($validator));
@@ -391,7 +371,7 @@ public function testRequiredValidation() {
     $empty_violation_list = $this->getMockBuilder('\Symfony\Component\Validator\ConstraintViolationList')
       ->setMethods(NULL)
       ->getMock();
-    $validator->expects($this->at(0))
+    $validator->expects($this->once())
       ->method('validate')
       ->with($this->entity->getTypedData())
       ->will($this->returnValue($empty_violation_list));
@@ -446,20 +426,13 @@ public function testBundle() {
   public function testAccess() {
     $access = $this->createMock('\Drupal\Core\Entity\EntityAccessControlHandlerInterface');
     $operation = $this->randomMachineName();
-    $access->expects($this->at(0))
+    $access->expects($this->exactly(2))
       ->method('access')
       ->with($this->entity, $operation)
-      ->will($this->returnValue(TRUE));
-    $access->expects($this->at(1))
-      ->method('access')
-      ->with($this->entity, $operation)
-      ->will($this->returnValue(AccessResult::allowed()));
-    $access->expects($this->at(2))
-      ->method('createAccess')
-      ->will($this->returnValue(TRUE));
-    $access->expects($this->at(3))
+      ->willReturnOnConsecutiveCalls(TRUE, AccessResult::allowed());
+    $access->expects($this->exactly(2))
       ->method('createAccess')
-      ->will($this->returnValue(AccessResult::allowed()));
+      ->willReturnOnConsecutiveCalls(TRUE, AccessResult::allowed());
     $this->entityTypeManager->expects($this->exactly(4))
       ->method('getAccessControlHandler')
       ->will($this->returnValue($access));
diff --git a/web/core/tests/Drupal/Tests/Core/Entity/Enhancer/EntityRouteEnhancerTest.php b/web/core/tests/Drupal/Tests/Core/Entity/Enhancer/EntityRouteEnhancerTest.php
index 7ede8bb2db..3f41a39300 100644
--- a/web/core/tests/Drupal/Tests/Core/Entity/Enhancer/EntityRouteEnhancerTest.php
+++ b/web/core/tests/Drupal/Tests/Core/Entity/Enhancer/EntityRouteEnhancerTest.php
@@ -54,8 +54,8 @@ public function testEnhancer() {
     $defaults['_route_object'] = (new Route('/test', $defaults));
     $defaults = $route_enhancer->enhance($defaults, $request);
     $this->assertEquals('\Drupal\Core\Entity\Controller\EntityViewController::view', $defaults['_controller'], 'The entity view controller was not set.');
-    $this->assertEquals($defaults['_entity'], 'Mock entity');
-    $this->assertEquals($defaults['view_mode'], 'full');
+    $this->assertEquals('Mock entity', $defaults['_entity']);
+    $this->assertEquals('full', $defaults['view_mode']);
     $this->assertFalse(isset($defaults['_entity_view']));
 
     // Set _entity_view and ensure that the entity view controller is set using
@@ -73,8 +73,8 @@ public function testEnhancer() {
     $defaults[RouteObjectInterface::ROUTE_OBJECT] = $route;
     $defaults = $route_enhancer->enhance($defaults, $request);
     $this->assertEquals('\Drupal\Core\Entity\Controller\EntityViewController::view', $defaults['_controller'], 'The entity view controller was not set.');
-    $this->assertEquals($defaults['_entity'], 'Mock entity');
-    $this->assertEquals($defaults['view_mode'], 'full');
+    $this->assertEquals('Mock entity', $defaults['_entity']);
+    $this->assertEquals('full', $defaults['view_mode']);
     $this->assertFalse(isset($defaults['_entity_view']));
 
     // Set _entity_view without a view mode.
@@ -84,7 +84,7 @@ public function testEnhancer() {
     $defaults['_route_object'] = (new Route('/test', $defaults));
     $defaults = $route_enhancer->enhance($defaults, $request);
     $this->assertEquals('\Drupal\Core\Entity\Controller\EntityViewController::view', $defaults['_controller'], 'The entity view controller was not set.');
-    $this->assertEquals($defaults['_entity'], 'Mock entity');
+    $this->assertEquals('Mock entity', $defaults['_entity']);
     $this->assertTrue(empty($defaults['view_mode']));
     $this->assertFalse(isset($defaults['_entity_view']));
   }
diff --git a/web/core/tests/Drupal/Tests/Core/Entity/EntityUnitTest.php b/web/core/tests/Drupal/Tests/Core/Entity/EntityUnitTest.php
index 3edaf4c7f9..74cbfa2392 100644
--- a/web/core/tests/Drupal/Tests/Core/Entity/EntityUnitTest.php
+++ b/web/core/tests/Drupal/Tests/Core/Entity/EntityUnitTest.php
@@ -195,11 +195,11 @@ public function testLabel() {
   public function testAccess() {
     $access = $this->createMock('\Drupal\Core\Entity\EntityAccessControlHandlerInterface');
     $operation = $this->randomMachineName();
-    $access->expects($this->at(0))
+    $access->expects($this->once())
       ->method('access')
       ->with($this->entity, $operation)
       ->will($this->returnValue(AccessResult::allowed()));
-    $access->expects($this->at(1))
+    $access->expects($this->once())
       ->method('createAccess')
       ->will($this->returnValue(AccessResult::allowed()));
     $this->entityTypeManager->expects($this->exactly(2))
@@ -396,19 +396,21 @@ public function testPreSave() {
    * @covers ::postSave
    */
   public function testPostSave() {
-    $this->cacheTagsInvalidator->expects($this->at(0))
+    $this->cacheTagsInvalidator->expects($this->exactly(2))
       ->method('invalidateTags')
-      ->with([
-        // List cache tag.
-        $this->entityTypeId . '_list',
-      ]);
-    $this->cacheTagsInvalidator->expects($this->at(1))
-      ->method('invalidateTags')
-      ->with([
-        // Own cache tag.
-        $this->entityTypeId . ':' . $this->values['id'],
-        // List cache tag.
-        $this->entityTypeId . '_list',
+      ->withConsecutive([
+        [
+          // List cache tag.
+          $this->entityTypeId . '_list',
+        ],
+      ],
+      [
+        [
+          // Own cache tag.
+          $this->entityTypeId . ':' . $this->values['id'],
+          // List cache tag.
+          $this->entityTypeId . '_list',
+        ],
       ]);
 
     // This method is internal, so check for errors on calling it only.
@@ -425,21 +427,23 @@ public function testPostSave() {
    * @covers ::postSave
    */
   public function testPostSaveBundle() {
-    $this->cacheTagsInvalidator->expects($this->at(0))
-      ->method('invalidateTags')
-      ->with([
-        // List cache tag.
-        $this->entityTypeId . '_list',
-        $this->entityTypeId . '_list:' . $this->entity->bundle(),
-      ]);
-    $this->cacheTagsInvalidator->expects($this->at(1))
+    $this->cacheTagsInvalidator->expects($this->exactly(2))
       ->method('invalidateTags')
-      ->with([
-        // Own cache tag.
-        $this->entityTypeId . ':' . $this->values['id'],
-        // List cache tag.
-        $this->entityTypeId . '_list',
-        $this->entityTypeId . '_list:' . $this->entity->bundle(),
+      ->withConsecutive([
+        [
+          // List cache tag.
+          $this->entityTypeId . '_list',
+          $this->entityTypeId . '_list:' . $this->entity->bundle(),
+        ],
+      ],
+      [
+        [
+          // Own cache tag.
+          $this->entityTypeId . ':' . $this->values['id'],
+          // List cache tag.
+          $this->entityTypeId . '_list',
+          $this->entityTypeId . '_list:' . $this->entity->bundle(),
+        ],
       ]);
 
     $this->entityType->expects($this->atLeastOnce())
diff --git a/web/core/tests/Drupal/Tests/Core/Entity/EntityUrlTest.php b/web/core/tests/Drupal/Tests/Core/Entity/EntityUrlTest.php
index 313fd544cd..6a39d8b9c1 100644
--- a/web/core/tests/Drupal/Tests/Core/Entity/EntityUrlTest.php
+++ b/web/core/tests/Drupal/Tests/Core/Entity/EntityUrlTest.php
@@ -395,7 +395,7 @@ public function testUriRelationships() {
     // Test route with no mandatory parameters.
     $this->registerLinkTemplate('canonical');
     $route_name_0 = 'entity.' . $this->entityTypeId . '.canonical';
-    $url_generator->expects($this->at(0))
+    $url_generator->expects($this->any())
       ->method('generateFromRoute')
       ->with($route_name_0)
       ->willReturn((new GeneratedUrl())->setGeneratedUrl('/entity_test'));
@@ -404,7 +404,7 @@ public function testUriRelationships() {
     // Test route with non-default mandatory parameters.
     $this->registerLinkTemplate('{non_default_parameter}');
     $route_name_1 = 'entity.' . $this->entityTypeId . '.{non_default_parameter}';
-    $url_generator->expects($this->at(0))
+    $url_generator->expects($this->any())
       ->method('generateFromRoute')
       ->with($route_name_1)
       ->willThrowException(new MissingMandatoryParametersException());
diff --git a/web/core/tests/Drupal/Tests/Core/Entity/KeyValueStore/KeyValueEntityStorageTest.php b/web/core/tests/Drupal/Tests/Core/Entity/KeyValueStore/KeyValueEntityStorageTest.php
index ead39ac8df..c9b3193a23 100644
--- a/web/core/tests/Drupal/Tests/Core/Entity/KeyValueStore/KeyValueEntityStorageTest.php
+++ b/web/core/tests/Drupal/Tests/Core/Entity/KeyValueStore/KeyValueEntityStorageTest.php
@@ -155,12 +155,9 @@ public function testCreateWithPredefinedUuid() {
       ->will($this->returnValue(get_class($this->getMockEntity())));
     $this->setUpKeyValueEntityStorage();
 
-    $this->moduleHandler->expects($this->at(0))
+    $this->moduleHandler->expects($this->exactly(2))
       ->method('invokeAll')
-      ->with('test_entity_type_create');
-    $this->moduleHandler->expects($this->at(1))
-      ->method('invokeAll')
-      ->with('entity_create');
+      ->withConsecutive(['test_entity_type_create'], ['entity_create']);
     $this->uuidService->expects($this->never())
       ->method('generate');
 
@@ -181,12 +178,9 @@ public function testCreateWithoutUuidKey() {
       ->will($this->returnValue(get_class($this->getMockEntity())));
     $this->setUpKeyValueEntityStorage(NULL);
 
-    $this->moduleHandler->expects($this->at(0))
-      ->method('invokeAll')
-      ->with('test_entity_type_create');
-    $this->moduleHandler->expects($this->at(1))
+    $this->moduleHandler->expects($this->exactly(2))
       ->method('invokeAll')
-      ->with('entity_create');
+      ->withConsecutive(['test_entity_type_create'], ['entity_create']);
     $this->uuidService->expects($this->never())
       ->method('generate');
 
@@ -209,12 +203,9 @@ public function testCreate() {
       ->will($this->returnValue(get_class($entity)));
     $this->setUpKeyValueEntityStorage();
 
-    $this->moduleHandler->expects($this->at(0))
+    $this->moduleHandler->expects($this->exactly(2))
       ->method('invokeAll')
-      ->with('test_entity_type_create');
-    $this->moduleHandler->expects($this->at(1))
-      ->method('invokeAll')
-      ->with('entity_create');
+      ->withConsecutive(['test_entity_type_create'], ['entity_create']);
     $this->uuidService->expects($this->once())
       ->method('generate')
       ->will($this->returnValue('bar'));
@@ -256,18 +247,14 @@ public function testSaveInsert(EntityInterface $entity) {
       ->method('toArray')
       ->will($this->returnValue($expected));
 
-    $this->moduleHandler->expects($this->at(0))
-      ->method('invokeAll')
-      ->with('test_entity_type_presave');
-    $this->moduleHandler->expects($this->at(1))
+    $this->moduleHandler->expects($this->exactly(4))
       ->method('invokeAll')
-      ->with('entity_presave');
-    $this->moduleHandler->expects($this->at(2))
-      ->method('invokeAll')
-      ->with('test_entity_type_insert');
-    $this->moduleHandler->expects($this->at(3))
-      ->method('invokeAll')
-      ->with('entity_insert');
+      ->withConsecutive(
+        ['test_entity_type_presave'],
+        ['entity_presave'],
+        ['test_entity_type_insert'],
+        ['entity_insert'],
+      );
     $this->keyValueStore->expects($this->once())
       ->method('set')
       ->with('foo', $expected);
@@ -304,26 +291,18 @@ public function testSaveUpdate(EntityInterface $entity) {
     $this->keyValueStore->expects($this->never())
       ->method('delete');
 
-    $this->moduleHandler->expects($this->at(0))
+    $this->moduleHandler->expects($this->exactly(2))
       ->method('getImplementations')
-      ->with('entity_load')
+      ->withConsecutive(['entity_load'], ['test_entity_type_load'])
       ->will($this->returnValue([]));
-    $this->moduleHandler->expects($this->at(1))
-      ->method('getImplementations')
-      ->with('test_entity_type_load')
-      ->will($this->returnValue([]));
-    $this->moduleHandler->expects($this->at(2))
-      ->method('invokeAll')
-      ->with('test_entity_type_presave');
-    $this->moduleHandler->expects($this->at(3))
-      ->method('invokeAll')
-      ->with('entity_presave');
-    $this->moduleHandler->expects($this->at(4))
+    $this->moduleHandler->expects($this->exactly(4))
       ->method('invokeAll')
-      ->with('test_entity_type_update');
-    $this->moduleHandler->expects($this->at(5))
-      ->method('invokeAll')
-      ->with('entity_update');
+      ->withConsecutive(
+        ['test_entity_type_presave'],
+        ['entity_presave'],
+        ['test_entity_type_update'],
+        ['entity_update'],
+      );
     $this->keyValueStore->expects($this->once())
       ->method('set')
       ->with('foo', $expected);
@@ -379,13 +358,9 @@ public function testSaveRenameConfigEntity(ConfigEntityInterface $entity) {
       ->will($this->returnValue(get_class($entity)));
     $this->setUpKeyValueEntityStorage();
 
-    $this->moduleHandler->expects($this->at(0))
-      ->method('getImplementations')
-      ->with('entity_load')
-      ->will($this->returnValue([]));
-    $this->moduleHandler->expects($this->at(1))
+    $this->moduleHandler->expects($this->exactly(2))
       ->method('getImplementations')
-      ->with('test_entity_type_load')
+      ->withConsecutive(['entity_load'], ['test_entity_type_load'])
       ->will($this->returnValue([]));
     $expected = ['id' => 'foo'];
     $entity->expects($this->once())
@@ -506,13 +481,9 @@ public function testLoad() {
       ->method('getMultiple')
       ->with(['foo'])
       ->will($this->returnValue([['id' => 'foo']]));
-    $this->moduleHandler->expects($this->at(0))
+    $this->moduleHandler->expects($this->exactly(2))
       ->method('getImplementations')
-      ->with('entity_load')
-      ->will($this->returnValue([]));
-    $this->moduleHandler->expects($this->at(1))
-      ->method('getImplementations')
-      ->with('test_entity_type_load')
+      ->withConsecutive(['entity_load'], ['test_entity_type_load'])
       ->will($this->returnValue([]));
     $entity = $this->entityStorage->load('foo');
     $this->assertInstanceOf('Drupal\Core\Entity\EntityInterface', $entity);
@@ -554,13 +525,9 @@ public function testLoadMultipleAll() {
     $this->keyValueStore->expects($this->once())
       ->method('getAll')
       ->will($this->returnValue([['id' => 'foo'], ['id' => 'bar']]));
-    $this->moduleHandler->expects($this->at(0))
-      ->method('getImplementations')
-      ->with('entity_load')
-      ->will($this->returnValue([]));
-    $this->moduleHandler->expects($this->at(1))
+    $this->moduleHandler->expects($this->exactly(2))
       ->method('getImplementations')
-      ->with('test_entity_type_load')
+      ->withConsecutive(['entity_load'], ['test_entity_type_load'])
       ->will($this->returnValue([]));
     $entities = $this->entityStorage->loadMultiple();
     foreach ($entities as $id => $entity) {
@@ -588,13 +555,9 @@ public function testLoadMultipleIds() {
       ->method('getMultiple')
       ->with(['foo'])
       ->will($this->returnValue([['id' => 'foo']]));
-    $this->moduleHandler->expects($this->at(0))
+    $this->moduleHandler->expects($this->exactly(2))
       ->method('getImplementations')
-      ->with('entity_load')
-      ->will($this->returnValue([]));
-    $this->moduleHandler->expects($this->at(1))
-      ->method('getImplementations')
-      ->with('test_entity_type_load')
+      ->withConsecutive(['entity_load'], ['test_entity_type_load'])
       ->will($this->returnValue([]));
     $entities = $this->entityStorage->loadMultiple(['foo']);
     foreach ($entities as $id => $entity) {
@@ -633,30 +596,12 @@ public function testDelete() {
       ->will($this->returnValue(get_class(reset($entities))));
     $this->setUpKeyValueEntityStorage();
 
-    $this->moduleHandler->expects($this->at(0))
-      ->method('invokeAll')
-      ->with('test_entity_type_predelete');
-    $this->moduleHandler->expects($this->at(1))
-      ->method('invokeAll')
-      ->with('entity_predelete');
-    $this->moduleHandler->expects($this->at(2))
-      ->method('invokeAll')
-      ->with('test_entity_type_predelete');
-    $this->moduleHandler->expects($this->at(3))
-      ->method('invokeAll')
-      ->with('entity_predelete');
-    $this->moduleHandler->expects($this->at(4))
-      ->method('invokeAll')
-      ->with('test_entity_type_delete');
-    $this->moduleHandler->expects($this->at(5))
-      ->method('invokeAll')
-      ->with('entity_delete');
-    $this->moduleHandler->expects($this->at(6))
-      ->method('invokeAll')
-      ->with('test_entity_type_delete');
-    $this->moduleHandler->expects($this->at(7))
+    $this->moduleHandler->expects($this->exactly(8))
       ->method('invokeAll')
-      ->with('entity_delete');
+      ->withConsecutive(
+        ['test_entity_type_predelete'],
+        ['entity_predelete'],
+      );
 
     $this->keyValueStore->expects($this->once())
       ->method('deleteMultiple')
diff --git a/web/core/tests/Drupal/Tests/Core/Entity/Sql/SqlContentEntityStorageSchemaTest.php b/web/core/tests/Drupal/Tests/Core/Entity/Sql/SqlContentEntityStorageSchemaTest.php
index a4e29b0f9e..7473c360b6 100644
--- a/web/core/tests/Drupal/Tests/Core/Entity/Sql/SqlContentEntityStorageSchemaTest.php
+++ b/web/core/tests/Drupal/Tests/Core/Entity/Sql/SqlContentEntityStorageSchemaTest.php
@@ -1536,12 +1536,12 @@ public function testonEntityTypeUpdateWithNewIndex() {
       ]);
 
     // The original indexes should be dropped before the new one is added.
-    $this->dbSchemaHandler->expects($this->at(0))
+    $this->dbSchemaHandler->expects($this->exactly(3))
       ->method('dropIndex')
-      ->with('entity_test', 'entity_test__b588603cb9');
-    $this->dbSchemaHandler->expects($this->at(1))
-      ->method('dropIndex')
-      ->with('entity_test', 'entity_test__removed_field');
+      ->withConsecutive(
+        ['entity_test', 'entity_test__b588603cb9'],
+        ['entity_test', 'entity_test__removed_field'],
+      );
 
     $this->dbSchemaHandler->expects($this->atLeastOnce())
       ->method('fieldExists')
diff --git a/web/core/tests/Drupal/Tests/Core/Extension/InfoParserUnitTest.php b/web/core/tests/Drupal/Tests/Core/Extension/InfoParserUnitTest.php
index a265c6fec9..da707e09b6 100644
--- a/web/core/tests/Drupal/Tests/Core/Extension/InfoParserUnitTest.php
+++ b/web/core/tests/Drupal/Tests/Core/Extension/InfoParserUnitTest.php
@@ -519,9 +519,9 @@ public function testInfoParserCommonInfo() {
         ],
       ]);
       $info_values = $this->infoParser->parse(vfsStream::url("modules/fixtures/$filename"));
-      $this->assertEquals($info_values['simple_string'], 'A simple string', 'Simple string value was parsed correctly.');
-      $this->assertEquals($info_values['version'], \Drupal::VERSION, 'Constant value was parsed correctly.');
-      $this->assertEquals($info_values['double_colon'], 'dummyClassName::method', 'Value containing double-colon was parsed correctly.');
+      $this->assertEquals('A simple string', $info_values['simple_string'], 'Simple string value was parsed correctly.');
+      $this->assertEquals(\Drupal::VERSION, $info_values['version'], 'Constant value was parsed correctly.');
+      $this->assertEquals('dummyClassName::method', $info_values['double_colon'], 'Value containing double-colon was parsed correctly.');
       $this->assertFalse($info_values['core_incompatible']);
     }
   }
@@ -548,7 +548,7 @@ public function testInfoParserCoreInfo() {
       ],
     ]);
     $info_values = $this->infoParser->parse(vfsStream::url("core/fixtures/$filename"));
-    $this->assertEquals($info_values['version'], \Drupal::VERSION, 'Constant value was parsed correctly.');
+    $this->assertEquals(\Drupal::VERSION, $info_values['version'], 'Constant value was parsed correctly.');
     $this->assertFalse($info_values['core_incompatible']);
     $this->assertEquals(\Drupal::VERSION, $info_values['core_version_requirement']);
   }
diff --git a/web/core/tests/Drupal/Tests/Core/Extension/ModuleHandlerTest.php b/web/core/tests/Drupal/Tests/Core/Extension/ModuleHandlerTest.php
index a6170683b8..0a55bfdc8d 100644
--- a/web/core/tests/Drupal/Tests/Core/Extension/ModuleHandlerTest.php
+++ b/web/core/tests/Drupal/Tests/Core/Extension/ModuleHandlerTest.php
@@ -113,17 +113,15 @@ public function testModuleReloading() {
       ])
       ->setMethods(['load'])
       ->getMock();
-    // First reload.
-    $module_handler->expects($this->at(0))
+    $module_handler->expects($this->exactly(3))
       ->method('load')
-      ->with($this->equalTo('module_handler_test'));
-    // Second reload.
-    $module_handler->expects($this->at(1))
-      ->method('load')
-      ->with($this->equalTo('module_handler_test'));
-    $module_handler->expects($this->at(2))
-      ->method('load')
-      ->with($this->equalTo('module_handler_test_added'));
+      ->withConsecutive(
+        // First reload.
+        ['module_handler_test'],
+        // Second reload.
+        ['module_handler_test'],
+        ['module_handler_test_added'],
+      );
     $module_handler->reload();
     $module_handler->addModule('module_handler_test_added', 'core/tests/Drupal/Tests/Core/Extension/modules/module_handler_test_added');
     $module_handler->reload();
@@ -187,7 +185,7 @@ public function testSetModuleList() {
     $module_handler->expects($this->once())->method('resetImplementations');
 
     // Make sure we're starting empty.
-    $this->assertEquals($module_handler->getModuleList(), []);
+    $this->assertEquals([], $module_handler->getModuleList());
 
     // Replace the list with a prebuilt list.
     $module_handler->setModuleList($fixture_module_handler->getModuleList());
diff --git a/web/core/tests/Drupal/Tests/Core/Extension/ThemeHandlerTest.php b/web/core/tests/Drupal/Tests/Core/Extension/ThemeHandlerTest.php
index fe2ca19033..fcf69c16bb 100644
--- a/web/core/tests/Drupal/Tests/Core/Extension/ThemeHandlerTest.php
+++ b/web/core/tests/Drupal/Tests/Core/Extension/ThemeHandlerTest.php
@@ -74,10 +74,10 @@ protected function setUp(): void {
    * @see \Drupal\Core\Extension\ThemeHandler::rebuildThemeData()
    */
   public function testRebuildThemeData() {
-    $this->themeList->expects($this->at(0))
+    $this->themeList->expects($this->once())
       ->method('reset')
       ->willReturnSelf();
-    $this->themeList->expects($this->at(1))
+    $this->themeList->expects($this->once())
       ->method('getList')
       ->will($this->returnValue([
         'seven' => new Extension($this->root, 'theme', 'core/themes/seven/seven.info.yml', 'seven.theme'),
diff --git a/web/core/tests/Drupal/Tests/Core/Form/FormCacheTest.php b/web/core/tests/Drupal/Tests/Core/Form/FormCacheTest.php
index 3180588d7f..f589f89c40 100644
--- a/web/core/tests/Drupal/Tests/Core/Form/FormCacheTest.php
+++ b/web/core/tests/Drupal/Tests/Core/Form/FormCacheTest.php
@@ -311,12 +311,12 @@ public function testLoadCachedFormStateWithFiles() {
         ],
       ],
     ];
-    $this->moduleHandler->expects($this->at(0))
+    $this->moduleHandler->expects($this->exactly(2))
       ->method('loadInclude')
-      ->with('a_module', 'the_type', 'some_name');
-    $this->moduleHandler->expects($this->at(1))
-      ->method('loadInclude')
-      ->with('another_module', 'inc', 'another_module');
+      ->withConsecutive(
+        ['a_module', 'the_type', 'some_name'],
+        ['another_module', 'inc', 'another_module'],
+      );
     $this->formStateCacheStore->expects($this->once())
       ->method('get')
       ->with($form_build_id)
diff --git a/web/core/tests/Drupal/Tests/Core/Form/FormErrorHandlerTest.php b/web/core/tests/Drupal/Tests/Core/Form/FormErrorHandlerTest.php
index d0bd954747..8087c3e4a4 100644
--- a/web/core/tests/Drupal/Tests/Core/Form/FormErrorHandlerTest.php
+++ b/web/core/tests/Drupal/Tests/Core/Form/FormErrorHandlerTest.php
@@ -48,24 +48,16 @@ protected function setUp(): void {
    * @covers ::displayErrorMessages
    */
   public function testDisplayErrorMessages() {
-    $this->messenger->expects($this->at(0))
+    $this->messenger->expects($this->exactly(6))
       ->method('addMessage')
-      ->with('invalid', 'error');
-    $this->messenger->expects($this->at(1))
-      ->method('addMessage')
-      ->with('invalid', 'error');
-    $this->messenger->expects($this->at(2))
-      ->method('addMessage')
-      ->with('invalid', 'error');
-    $this->messenger->expects($this->at(3))
-      ->method('addMessage')
-      ->with('no title given', 'error');
-    $this->messenger->expects($this->at(4))
-      ->method('addMessage')
-      ->with('element is invisible', 'error');
-    $this->messenger->expects($this->at(5))
-      ->method('addMessage')
-      ->with('this missing element is invalid', 'error');
+      ->withConsecutive(
+        ['invalid', 'error'],
+        ['invalid', 'error'],
+        ['invalid', 'error'],
+        ['no title given', 'error'],
+        ['element is invisible', 'error'],
+        ['this missing element is invalid', 'error'],
+      );
 
     $form = [
       '#parents' => [],
diff --git a/web/core/tests/Drupal/Tests/Core/Logger/LoggerChannelTest.php b/web/core/tests/Drupal/Tests/Core/Logger/LoggerChannelTest.php
index 899c5b57e6..641f9f9c83 100644
--- a/web/core/tests/Drupal/Tests/Core/Logger/LoggerChannelTest.php
+++ b/web/core/tests/Drupal/Tests/Core/Logger/LoggerChannelTest.php
@@ -94,7 +94,7 @@ public function testSortLoggers() {
 
     $channel->log(rand(0, 7), $this->randomMachineName());
     // Ensure that the logger added in the end fired first.
-    $this->assertEquals($index_order, '3210');
+    $this->assertEquals('3210', $index_order);
   }
 
   /**
diff --git a/web/core/tests/Drupal/Tests/Core/Menu/ContextualLinkManagerTest.php b/web/core/tests/Drupal/Tests/Core/Menu/ContextualLinkManagerTest.php
index a56c883e37..cc780e6ba5 100644
--- a/web/core/tests/Drupal/Tests/Core/Menu/ContextualLinkManagerTest.php
+++ b/web/core/tests/Drupal/Tests/Core/Menu/ContextualLinkManagerTest.php
@@ -285,9 +285,12 @@ public function testGetContextualLinksArrayByGroup() {
       ->method('createInstance')
       ->will($this->returnValueMap($map));
 
-    $this->moduleHandler->expects($this->at(1))
+    $this->moduleHandler->expects($this->exactly(2))
       ->method('alter')
-      ->with($this->equalTo('contextual_links'), new Count(2), $this->equalTo('group1'), $this->equalTo(['key' => 'value']));
+      ->withConsecutive(
+        ['contextual_links_plugins'],
+        ['contextual_links', new Count(2), 'group1', ['key' => 'value']],
+      );
 
     $result = $this->contextualLinkManager->getContextualLinksArrayByGroup('group1', ['key' => 'value']);
     $this->assertCount(2, $result);
diff --git a/web/core/tests/Drupal/Tests/Core/Menu/DefaultMenuLinkTreeManipulatorsTest.php b/web/core/tests/Drupal/Tests/Core/Menu/DefaultMenuLinkTreeManipulatorsTest.php
index dfaf778900..73b008f773 100644
--- a/web/core/tests/Drupal/Tests/Core/Menu/DefaultMenuLinkTreeManipulatorsTest.php
+++ b/web/core/tests/Drupal/Tests/Core/Menu/DefaultMenuLinkTreeManipulatorsTest.php
@@ -291,15 +291,15 @@ public function testCheckNodeAccess() {
     ]);
 
     $query = $this->createMock('Drupal\Core\Entity\Query\QueryInterface');
-    $query->expects($this->at(0))
+    $query->expects($this->once())
       ->method('accessCheck')
       ->with(TRUE);
-    $query->expects($this->at(1))
-      ->method('condition')
-      ->with('nid', [1, 2, 3, 4]);
-    $query->expects($this->at(2))
+    $query->expects($this->exactly(2))
       ->method('condition')
-      ->with('status', NodeInterface::PUBLISHED);
+      ->withConsecutive(
+        ['nid', [1, 2, 3, 4]],
+        ['status', NodeInterface::PUBLISHED],
+      );
     $query->expects($this->once())
       ->method('execute')
       ->willReturn([1, 2, 4]);
@@ -328,14 +328,13 @@ public function testCheckNodeAccess() {
     // access checkers.
 
     // Ensure that the access manager is just called for the non-node routes.
-    $this->accessManager->expects($this->at(0))
-      ->method('checkNamedRoute')
-      ->with('test_route', [], $this->currentUser, TRUE)
-      ->willReturn(AccessResult::allowed());
-    $this->accessManager->expects($this->at(1))
+    $this->accessManager->expects($this->exactly(2))
       ->method('checkNamedRoute')
       ->with('test_route', [], $this->currentUser, TRUE)
-      ->willReturn(AccessResult::neutral());
+      ->willReturnOnConsecutiveCalls(
+        AccessResult::allowed(),
+        AccessResult::neutral(),
+      );
     $tree = $this->defaultMenuTreeManipulators->checkAccess($tree);
 
     $this->assertEquals($node_access_result, $tree[1]->access);
diff --git a/web/core/tests/Drupal/Tests/Core/Menu/LocalTaskManagerTest.php b/web/core/tests/Drupal/Tests/Core/Menu/LocalTaskManagerTest.php
index 3df272c87d..4de8170aaa 100644
--- a/web/core/tests/Drupal/Tests/Core/Menu/LocalTaskManagerTest.php
+++ b/web/core/tests/Drupal/Tests/Core/Menu/LocalTaskManagerTest.php
@@ -178,23 +178,18 @@ public function testGetLocalTaskForRouteWithEmptyCache() {
 
     $result = $this->getLocalTasksForRouteResult($mock_plugin);
 
-    $this->cacheBackend->expects($this->at(0))
+    $this->cacheBackend->expects($this->exactly(2))
       ->method('get')
-      ->with('local_task_plugins:en:menu_local_task_test_tasks_view');
-
-    $this->cacheBackend->expects($this->at(1))
-      ->method('get')
-      ->with('local_task_plugins:en');
-
-    $this->cacheBackend->expects($this->at(2))
-      ->method('set')
-      ->with('local_task_plugins:en', $definitions, Cache::PERMANENT);
-
-    $expected_set = $this->getLocalTasksCache();
-
-    $this->cacheBackend->expects($this->at(3))
+      ->withConsecutive(
+        ['local_task_plugins:en:menu_local_task_test_tasks_view'],
+        ['local_task_plugins:en'],
+      );
+    $this->cacheBackend->expects($this->exactly(2))
       ->method('set')
-      ->with('local_task_plugins:en:menu_local_task_test_tasks_view', $expected_set, Cache::PERMANENT, ['local_task']);
+      ->withConsecutive(
+        ['local_task_plugins:en', $definitions, Cache::PERMANENT],
+        ['local_task_plugins:en:menu_local_task_test_tasks_view', $this->getLocalTasksCache(), Cache::PERMANENT, ['local_task']],
+      );
 
     $local_tasks = $this->manager->getLocalTasksForRoute('menu_local_task_test_tasks_view');
     $this->assertEquals($result, $local_tasks);
@@ -214,7 +209,7 @@ public function testGetLocalTaskForRouteWithFilledCache() {
 
     $result = $this->getLocalTasksCache($mock_plugin);
 
-    $this->cacheBackend->expects($this->at(0))
+    $this->cacheBackend->expects($this->once())
       ->method('get')
       ->with('local_task_plugins:en:menu_local_task_test_tasks_view')
       ->will($this->returnValue((object) ['data' => $result]));
diff --git a/web/core/tests/Drupal/Tests/Core/Menu/StaticMenuLinkOverridesTest.php b/web/core/tests/Drupal/Tests/Core/Menu/StaticMenuLinkOverridesTest.php
index 110da8a04e..97eac801ed 100644
--- a/web/core/tests/Drupal/Tests/Core/Menu/StaticMenuLinkOverridesTest.php
+++ b/web/core/tests/Drupal/Tests/Core/Menu/StaticMenuLinkOverridesTest.php
@@ -18,7 +18,7 @@ class StaticMenuLinkOverridesTest extends UnitTestCase {
    */
   public function testReload() {
     $config_factory = $this->createMock('Drupal\Core\Config\ConfigFactoryInterface');
-    $config_factory->expects($this->at(0))
+    $config_factory->expects($this->once())
       ->method('reset')
       ->with('core.menu.static_menu_link_overrides');
 
@@ -88,14 +88,6 @@ public function testSaveOverride() {
     $config = $this->getMockBuilder('Drupal\Core\Config\Config')
       ->disableOriginalConstructor()
       ->getMock();
-    $config->expects($this->at(0))
-      ->method('get')
-      ->with('definitions')
-      ->will($this->returnValue([]));
-    $config->expects($this->at(1))
-      ->method('get')
-      ->with('definitions')
-      ->will($this->returnValue([]));
 
     $definition_save_1 = [
       'definitions' => [
@@ -108,25 +100,24 @@ public function testSaveOverride() {
         'test1__la___ma' => ['parent' => 'test1', 'menu_name' => '', 'weight' => 0, 'expanded' => FALSE, 'enabled' => FALSE],
       ],
     ];
-    $config->expects($this->at(2))
-      ->method('set')
-      ->with('definitions', $definition_save_1['definitions'])
-      ->will($this->returnSelf());
-    $config->expects($this->at(3))
-      ->method('save');
-    $config->expects($this->at(4))
-      ->method('get')
-      ->with('definitions')
-      ->will($this->returnValue($definition_save_1['definitions']));
-    $config->expects($this->at(5))
+
+    $config->expects($this->exactly(4))
       ->method('get')
       ->with('definitions')
-      ->will($this->returnValue($definition_save_1['definitions']));
-    $config->expects($this->at(6))
+      ->willReturnOnConsecutiveCalls(
+        [],
+        [],
+        $definition_save_1['definitions'],
+        $definition_save_1['definitions'],
+      );
+    $config->expects($this->exactly(2))
       ->method('set')
-      ->with('definitions', $definitions_save_2['definitions'])
+      ->withConsecutive(
+        ['definitions', $definition_save_1['definitions']],
+        ['definitions', $definitions_save_2['definitions']],
+      )
       ->will($this->returnSelf());
-    $config->expects($this->at(7))
+    $config->expects($this->exactly(2))
       ->method('save');
 
     $config_factory = $this->createMock('Drupal\Core\Config\ConfigFactoryInterface');
@@ -156,20 +147,18 @@ public function testDeleteOverrides($ids, array $old_definitions, array $new_def
     $config = $this->getMockBuilder('Drupal\Core\Config\Config')
       ->disableOriginalConstructor()
       ->getMock();
-    $config->expects($this->at(0))
+    $config->expects($this->once())
       ->method('get')
       ->with('definitions')
       ->will($this->returnValue($old_definitions));
 
     // Only save if the definitions changes.
-    if ($old_definitions != $new_definitions) {
-      $config->expects($this->at(1))
-        ->method('set')
-        ->with('definitions', $new_definitions)
-        ->will($this->returnSelf());
-      $config->expects($this->at(2))
-        ->method('save');
-    }
+    $config->expects($old_definitions != $new_definitions ? $this->once() : $this->never())
+      ->method('set')
+      ->with('definitions', $new_definitions)
+      ->will($this->returnSelf());
+    $config->expects($old_definitions != $new_definitions ? $this->once() : $this->never())
+      ->method('save');
 
     $config_factory = $this->createMock('Drupal\Core\Config\ConfigFactoryInterface');
     $config_factory->expects($this->once())
diff --git a/web/core/tests/Drupal/Tests/Core/PageCache/NoSessionOpenTest.php b/web/core/tests/Drupal/Tests/Core/PageCache/NoSessionOpenTest.php
index f92d59df80..9f24716df8 100644
--- a/web/core/tests/Drupal/Tests/Core/PageCache/NoSessionOpenTest.php
+++ b/web/core/tests/Drupal/Tests/Core/PageCache/NoSessionOpenTest.php
@@ -41,15 +41,12 @@ public function testNoAllowUnlessSessionCookiePresent() {
     $request_without_session = new Request();
     $request_with_session = Request::create('/', 'GET', [], ['some-session-name' => 'some-session-id']);
 
-    $this->sessionConfiguration->expects($this->at(0))
+    $this->sessionConfiguration->expects($this->exactly(2))
       ->method('hasSession')
-      ->with($request_without_session)
-      ->will($this->returnValue(FALSE));
-
-    $this->sessionConfiguration->expects($this->at(1))
-      ->method('hasSession')
-      ->with($request_with_session)
-      ->will($this->returnValue(TRUE));
+      ->willReturnMap([
+        [$request_without_session, FALSE],
+        [$request_with_session, TRUE],
+      ]);
 
     $result = $this->policy->check($request_without_session);
     $this->assertSame(RequestPolicyInterface::ALLOW, $result);
diff --git a/web/core/tests/Drupal/Tests/Core/Plugin/Discovery/DerivativeDiscoveryDecoratorTest.php b/web/core/tests/Drupal/Tests/Core/Plugin/Discovery/DerivativeDiscoveryDecoratorTest.php
index a8f61b45b0..12bf5e343c 100644
--- a/web/core/tests/Drupal/Tests/Core/Plugin/Discovery/DerivativeDiscoveryDecoratorTest.php
+++ b/web/core/tests/Drupal/Tests/Core/Plugin/Discovery/DerivativeDiscoveryDecoratorTest.php
@@ -239,14 +239,16 @@ public function testSingleExistingDerivative() {
       'null_value' => NULL,
     ];
 
-    $this->discoveryMain->expects($this->at(0))
+    $this->discoveryMain->expects($this->exactly(2))
       ->method('getDefinition')
-      ->with('non_container_aware_discovery:test_discovery_1')
-      ->will($this->returnValue($derivative_definition));
-    $this->discoveryMain->expects($this->at(1))
-      ->method('getDefinition')
-      ->with('non_container_aware_discovery')
-      ->will($this->returnValue($base_definition));
+      ->withConsecutive(
+        ['non_container_aware_discovery:test_discovery_1'],
+        ['non_container_aware_discovery'],
+      )
+      ->willReturnOnConsecutiveCalls(
+        $derivative_definition,
+        $base_definition,
+      );
 
     $discovery = new DerivativeDiscoveryDecorator($this->discoveryMain);
 
diff --git a/web/core/tests/Drupal/Tests/Core/Plugin/Discovery/HookDiscoveryTest.php b/web/core/tests/Drupal/Tests/Core/Plugin/Discovery/HookDiscoveryTest.php
index f528e5f631..9050534377 100644
--- a/web/core/tests/Drupal/Tests/Core/Plugin/Discovery/HookDiscoveryTest.php
+++ b/web/core/tests/Drupal/Tests/Core/Plugin/Discovery/HookDiscoveryTest.php
@@ -59,26 +59,24 @@ public function testGetDefinitions() {
       ->with('test_plugin')
       ->will($this->returnValue(['hook_discovery_test', 'hook_discovery_test2']));
 
-    $this->moduleHandler->expects($this->at(1))
+    $this->moduleHandler->expects($this->exactly(2))
       ->method('invoke')
-      ->with('hook_discovery_test', 'test_plugin')
-      ->will($this->returnValue($this->hookDiscoveryTestTestPlugin()));
-    $this->moduleHandler->expects($this->at(2))
-      ->method('invoke')
-      ->with('hook_discovery_test2', 'test_plugin')
-      ->will($this->returnValue($this->hookDiscoveryTest2TestPlugin()));
+      ->willReturnMap([
+        ['hook_discovery_test', 'test_plugin', [], $this->hookDiscoveryTestTestPlugin()],
+        ['hook_discovery_test2', 'test_plugin', [], $this->hookDiscoveryTest2TestPlugin()],
+      ]);
 
     $definitions = $this->hookDiscovery->getDefinitions();
 
     $this->assertCount(3, $definitions);
-    $this->assertEquals($definitions['test_id_1']['class'], 'Drupal\plugin_test\Plugin\plugin_test\fruit\Apple');
-    $this->assertEquals($definitions['test_id_2']['class'], 'Drupal\plugin_test\Plugin\plugin_test\fruit\Orange');
-    $this->assertEquals($definitions['test_id_3']['class'], 'Drupal\plugin_test\Plugin\plugin_test\fruit\Cherry');
+    $this->assertEquals('Drupal\plugin_test\Plugin\plugin_test\fruit\Apple', $definitions['test_id_1']['class']);
+    $this->assertEquals('Drupal\plugin_test\Plugin\plugin_test\fruit\Orange', $definitions['test_id_2']['class']);
+    $this->assertEquals('Drupal\plugin_test\Plugin\plugin_test\fruit\Cherry', $definitions['test_id_3']['class']);
 
     // Ensure that the module was set.
-    $this->assertEquals($definitions['test_id_1']['provider'], 'hook_discovery_test');
-    $this->assertEquals($definitions['test_id_2']['provider'], 'hook_discovery_test');
-    $this->assertEquals($definitions['test_id_3']['provider'], 'hook_discovery_test2');
+    $this->assertEquals('hook_discovery_test', $definitions['test_id_1']['provider']);
+    $this->assertEquals('hook_discovery_test', $definitions['test_id_2']['provider']);
+    $this->assertEquals('hook_discovery_test2', $definitions['test_id_3']['provider']);
   }
 
   /**
@@ -103,16 +101,16 @@ public function testGetDefinition() {
     $this->assertNull($this->hookDiscovery->getDefinition('test_non_existent', FALSE));
 
     $plugin_definition = $this->hookDiscovery->getDefinition('test_id_1');
-    $this->assertEquals($plugin_definition['class'], 'Drupal\plugin_test\Plugin\plugin_test\fruit\Apple');
-    $this->assertEquals($plugin_definition['provider'], 'hook_discovery_test');
+    $this->assertEquals('Drupal\plugin_test\Plugin\plugin_test\fruit\Apple', $plugin_definition['class']);
+    $this->assertEquals('hook_discovery_test', $plugin_definition['provider']);
 
     $plugin_definition = $this->hookDiscovery->getDefinition('test_id_2');
-    $this->assertEquals($plugin_definition['class'], 'Drupal\plugin_test\Plugin\plugin_test\fruit\Orange');
-    $this->assertEquals($plugin_definition['provider'], 'hook_discovery_test');
+    $this->assertEquals('Drupal\plugin_test\Plugin\plugin_test\fruit\Orange', $plugin_definition['class']);
+    $this->assertEquals('hook_discovery_test', $plugin_definition['provider']);
 
     $plugin_definition = $this->hookDiscovery->getDefinition('test_id_3');
-    $this->assertEquals($plugin_definition['class'], 'Drupal\plugin_test\Plugin\plugin_test\fruit\Cherry');
-    $this->assertEquals($plugin_definition['provider'], 'hook_discovery_test2');
+    $this->assertEquals('Drupal\plugin_test\Plugin\plugin_test\fruit\Cherry', $plugin_definition['class']);
+    $this->assertEquals('hook_discovery_test2', $plugin_definition['provider']);
   }
 
   /**
diff --git a/web/core/tests/Drupal/Tests/Core/Render/RendererTest.php b/web/core/tests/Drupal/Tests/Core/Render/RendererTest.php
index bb8fd7ce92..7d519335c7 100644
--- a/web/core/tests/Drupal/Tests/Core/Render/RendererTest.php
+++ b/web/core/tests/Drupal/Tests/Core/Render/RendererTest.php
@@ -264,11 +264,13 @@ public function providerTestRenderBasic() {
       '#attributes' => ['class' => ['baz']],
     ];
     $setup_code_type_link = function () {
-      $this->setupThemeContainer();
-      $this->themeManager->expects($this->at(0))
+      $this->themeManager->expects($this->exactly(2))
         ->method('render')
-        ->with('common_test_foo', $this->anything())
+        ->with($this->logicalOr('common_test_foo', 'container'))
         ->willReturnCallback(function ($theme, $vars) {
+          if ($theme == 'container') {
+            return '<div' . (string) (new Attribute($vars['#attributes'])) . '>' . $vars['#children'] . "</div>\n";
+          }
           return $vars['#foo'] . $vars['#bar'];
         });
     };
@@ -289,11 +291,13 @@ public function providerTestRenderBasic() {
       '#title' => 'bar',
     ];
     $setup_code_type_link = function () {
-      $this->setupThemeContainer();
-      $this->themeManager->expects($this->at(0))
+      $this->themeManager->expects($this->exactly(2))
         ->method('render')
-        ->with('link', $this->anything())
+        ->with($this->logicalOr('link', 'container'))
         ->willReturnCallback(function ($theme, $vars) {
+          if ($theme == 'container') {
+            return '<div' . (string) (new Attribute($vars['#attributes'])) . '>' . $vars['#children'] . "</div>\n";
+          }
           $attributes = new Attribute(['href' => $vars['#url']] + (isset($vars['#attributes']) ? $vars['#attributes'] : []));
           return '<a' . (string) $attributes . '>' . $vars['#title'] . '</a>';
         });
@@ -326,7 +330,12 @@ public function providerTestRenderBasic() {
       ],
     ];
     $setup_code = function () {
-      $this->setupThemeContainer($this->any());
+      $this->themeManager->expects($this->exactly(2))
+        ->method('render')
+        ->with('container')
+        ->willReturnCallback(function ($theme, $vars) {
+          return '<div' . (string) (new Attribute($vars['#attributes'])) . '>' . $vars['#children'] . "</div>\n";
+        });
     };
     $data[] = [$build, '<div class="foo"><div class="bar"></div>' . "\n" . '</div>' . "\n", $setup_code];
 
@@ -336,7 +345,12 @@ public function providerTestRenderBasic() {
       '#attributes' => ['class' => ['foo']],
     ];
     $setup_code = function () {
-      $this->setupThemeContainerMultiSuggestion($this->any());
+      $this->themeManager->expects($this->once())
+        ->method('render')
+        ->with(['container'])
+        ->willReturnCallback(function ($theme, $vars) {
+          return '<div' . (string) (new Attribute($vars['#attributes'])) . '>' . $vars['#children'] . "</div>\n";
+        });
     };
     $data[] = [$build, '<div class="foo"></div>' . "\n", $setup_code];
 
@@ -730,24 +744,6 @@ protected function assertAccess($build, $access) {
     }
   }
 
-  protected function setupThemeContainer($matcher = NULL) {
-    $this->themeManager->expects($matcher ?: $this->at(1))
-      ->method('render')
-      ->with('container', $this->anything())
-      ->willReturnCallback(function ($theme, $vars) {
-        return '<div' . (string) (new Attribute($vars['#attributes'])) . '>' . $vars['#children'] . "</div>\n";
-      });
-  }
-
-  protected function setupThemeContainerMultiSuggestion($matcher = NULL) {
-    $this->themeManager->expects($matcher ?: $this->at(1))
-      ->method('render')
-      ->with(['container'], $this->anything())
-      ->willReturnCallback(function ($theme, $vars) {
-        return '<div' . (string) (new Attribute($vars['#attributes'])) . '>' . $vars['#children'] . "</div>\n";
-      });
-  }
-
   /**
    * @covers ::render
    * @covers ::doRender
@@ -763,7 +759,7 @@ public function testRenderWithoutThemeArguments() {
       ->willReturn('foobar');
 
     // Test that defaults work.
-    $this->assertEquals($this->renderer->renderRoot($element), 'foobar', 'Defaults work');
+    $this->assertEquals('foobar', $this->renderer->renderRoot($element), 'Defaults work');
   }
 
   /**
diff --git a/web/core/tests/Drupal/Tests/Core/Routing/ContentTypeHeaderMatcherTest.php b/web/core/tests/Drupal/Tests/Core/Routing/ContentTypeHeaderMatcherTest.php
index cc2d004c92..4d36bc9e28 100644
--- a/web/core/tests/Drupal/Tests/Core/Routing/ContentTypeHeaderMatcherTest.php
+++ b/web/core/tests/Drupal/Tests/Core/Routing/ContentTypeHeaderMatcherTest.php
@@ -79,7 +79,7 @@ public function testJsonRequest() {
     $this->assertNotNull($routes->get('route_f'), 'The json route was found.');
     $this->assertNull($routes->get('route_g'), 'The xml route was not found.');
     foreach ($routes as $name => $route) {
-      $this->assertEquals($name, 'route_f', 'The json route is the first one in the collection.');
+      $this->assertEquals('route_f', $name, 'The json route is the first one in the collection.');
       break;
     }
   }
diff --git a/web/core/tests/Drupal/Tests/Core/Routing/RequestFormatRouteFilterTest.php b/web/core/tests/Drupal/Tests/Core/Routing/RequestFormatRouteFilterTest.php
index 4fff4c6607..22296418aa 100644
--- a/web/core/tests/Drupal/Tests/Core/Routing/RequestFormatRouteFilterTest.php
+++ b/web/core/tests/Drupal/Tests/Core/Routing/RequestFormatRouteFilterTest.php
@@ -29,7 +29,7 @@ public function testFilter(RouteCollection $collection, $request_format, array $
     $request->setRequestFormat($request_format);
     $collection = $route_filter->filter($collection, $request);
 
-    $this->assertCount(count($expected_filtered_collection), $collection);
+    $this->assertSameSize($expected_filtered_collection, $collection);
     $this->assertSame($expected_filtered_collection, array_keys($collection->all()));
   }
 
diff --git a/web/core/tests/Drupal/Tests/Core/Routing/RouteBuilderTest.php b/web/core/tests/Drupal/Tests/Core/Routing/RouteBuilderTest.php
index 59d4367e7e..8f8fb5aefa 100644
--- a/web/core/tests/Drupal/Tests/Core/Routing/RouteBuilderTest.php
+++ b/web/core/tests/Drupal/Tests/Core/Routing/RouteBuilderTest.php
@@ -159,13 +159,12 @@ public function testRebuildWithStaticModuleRoutes() {
     $route_build_event = new RouteBuildEvent($route_collection);
 
     // Ensure that the alter routes events are fired.
-    $this->dispatcher->expects($this->at(0))
+    $this->dispatcher->expects($this->atLeast(2))
       ->method('dispatch')
-      ->with($route_build_event, RoutingEvents::DYNAMIC);
-
-    $this->dispatcher->expects($this->at(1))
-      ->method('dispatch')
-      ->with($route_build_event, RoutingEvents::ALTER);
+      ->withConsecutive(
+        [$route_build_event, RoutingEvents::DYNAMIC],
+        [$route_build_event, RoutingEvents::ALTER],
+      );
 
     // Ensure that access checks are set.
     $this->checkProvider->expects($this->once())
@@ -173,10 +172,10 @@ public function testRebuildWithStaticModuleRoutes() {
       ->with($route_collection);
 
     // Ensure that the routes are set to the dumper and dumped.
-    $this->dumper->expects($this->at(0))
+    $this->dumper->expects($this->once())
       ->method('addRoutes')
       ->with($route_collection);
-    $this->dumper->expects($this->at(1))
+    $this->dumper->expects($this->once())
       ->method('dump')
       ->with();
 
@@ -229,13 +228,12 @@ public function testRebuildWithProviderBasedRoutes() {
     $route_build_event = new RouteBuildEvent($route_collection_filled);
 
     // Ensure that the alter routes events are fired.
-    $this->dispatcher->expects($this->at(0))
-      ->method('dispatch')
-      ->with($route_build_event, RoutingEvents::DYNAMIC);
-
-    $this->dispatcher->expects($this->at(1))
+    $this->dispatcher->expects($this->atLeast(2))
       ->method('dispatch')
-      ->with($route_build_event, RoutingEvents::ALTER);
+      ->withConsecutive(
+        [$route_build_event, RoutingEvents::DYNAMIC],
+        [$route_build_event, RoutingEvents::ALTER],
+      );
 
     // Ensure that access checks are set.
     $this->checkProvider->expects($this->once())
@@ -243,10 +241,10 @@ public function testRebuildWithProviderBasedRoutes() {
       ->with($route_collection_filled);
 
     // Ensure that the routes are set to the dumper and dumped.
-    $this->dumper->expects($this->at(0))
+    $this->dumper->expects($this->once())
       ->method('addRoutes')
       ->with($route_collection_filled);
-    $this->dumper->expects($this->at(1))
+    $this->dumper->expects($this->once())
       ->method('dump');
 
     $this->assertTrue($this->routeBuilder->rebuild());
@@ -312,9 +310,12 @@ public function testRebuildWithOverriddenRouteClass() {
     $route_collection_filled->add('test_route.override', new Route('/test_route_override', [], [], ['compiler_class' => 'Class\Does\Not\Exist']));
     $route_collection_filled->add('test_route', new Route('/test_route', [], [], ['compiler_class' => RouteCompiler::class]));
     $route_build_event = new RouteBuildEvent($route_collection_filled);
-    $this->dispatcher->expects($this->at(0))
+    $this->dispatcher->expects($this->atLeast(2))
       ->method('dispatch')
-      ->with($route_build_event, RoutingEvents::DYNAMIC);
+      ->withConsecutive(
+        [$route_build_event, RoutingEvents::DYNAMIC],
+        [$route_build_event, RoutingEvents::ALTER],
+      );
 
     $this->assertTrue($this->routeBuilder->rebuild());
   }
diff --git a/web/core/tests/Drupal/Tests/Core/Routing/RouteCompilerTest.php b/web/core/tests/Drupal/Tests/Core/Routing/RouteCompilerTest.php
index 0bce9a3369..2d283ebaa2 100644
--- a/web/core/tests/Drupal/Tests/Core/Routing/RouteCompilerTest.php
+++ b/web/core/tests/Drupal/Tests/Core/Routing/RouteCompilerTest.php
@@ -57,8 +57,8 @@ public function testCompilation() {
     $route->setOption('compiler_class', RouteCompiler::class);
     $compiled = $route->compile();
 
-    $this->assertEquals($compiled->getFit(), 5 /* That's 101 binary*/, 'The fit was incorrect.');
-    $this->assertEquals($compiled->getPatternOutline(), '/test/%/more', 'The pattern outline was not correct.');
+    $this->assertEquals(5 /* That's 101 binary*/, $compiled->getFit(), 'The fit was incorrect.');
+    $this->assertEquals('/test/%/more', $compiled->getPatternOutline(), 'The pattern outline was not correct.');
   }
 
   /**
@@ -73,8 +73,8 @@ public function testCompilationDefaultValue() {
     $route->setOption('compiler_class', RouteCompiler::class);
     $compiled = $route->compile();
 
-    $this->assertEquals($compiled->getFit(), 5 /* That's 101 binary*/, 'The fit was not correct.');
-    $this->assertEquals($compiled->getPatternOutline(), '/test/%/more', 'The pattern outline was not correct.');
+    $this->assertEquals(5  /* That's 101 binary*/, $compiled->getFit(), 'The fit was not correct.');
+    $this->assertEquals('/test/%/more', $compiled->getPatternOutline(), 'The pattern outline was not correct.');
   }
 
 }
diff --git a/web/core/tests/Drupal/Tests/Core/Routing/UrlGeneratorTest.php b/web/core/tests/Drupal/Tests/Core/Routing/UrlGeneratorTest.php
index 1c537f3f7a..fc4ea09e3d 100644
--- a/web/core/tests/Drupal/Tests/Core/Routing/UrlGeneratorTest.php
+++ b/web/core/tests/Drupal/Tests/Core/Routing/UrlGeneratorTest.php
@@ -390,7 +390,7 @@ public function testGetPathFromRouteTrailing() {
       ->method('processOutbound');
 
     $path = $this->generator->getPathFromRoute('test_3');
-    $this->assertEquals($path, 'test/two');
+    $this->assertEquals('test/two', $path);
   }
 
   /**
diff --git a/web/core/tests/Drupal/Tests/Core/Session/WriteSafeSessionHandlerTest.php b/web/core/tests/Drupal/Tests/Core/Session/WriteSafeSessionHandlerTest.php
index 954a290f67..e458375152 100644
--- a/web/core/tests/Drupal/Tests/Core/Session/WriteSafeSessionHandlerTest.php
+++ b/web/core/tests/Drupal/Tests/Core/Session/WriteSafeSessionHandlerTest.php
@@ -46,15 +46,10 @@ public function testConstructWriteSafeSessionHandlerDefaultArgs() {
     $this->assertTrue($this->sessionHandler->isSessionWritable());
 
     // Writing should be enabled, return value passed to the caller by default.
-    $this->wrappedSessionHandler->expects($this->at(0))
+    $this->wrappedSessionHandler->expects($this->exactly(2))
       ->method('write')
       ->with($session_id, $session_data)
-      ->will($this->returnValue(TRUE));
-
-    $this->wrappedSessionHandler->expects($this->at(1))
-      ->method('write')
-      ->with($session_id, $session_data)
-      ->will($this->returnValue(FALSE));
+      ->willReturnOnConsecutiveCalls(TRUE, FALSE);
 
     $result = $this->sessionHandler->write($session_id, $session_data);
     $this->assertTrue($result);
@@ -111,15 +106,10 @@ public function testSetSessionWritable() {
     $this->assertTrue($this->sessionHandler->isSessionWritable());
 
     // Writing should be enabled, return value passed to the caller by default.
-    $this->wrappedSessionHandler->expects($this->at(0))
-      ->method('write')
-      ->with($session_id, $session_data)
-      ->will($this->returnValue(TRUE));
-
-    $this->wrappedSessionHandler->expects($this->at(1))
+    $this->wrappedSessionHandler->expects($this->exactly(2))
       ->method('write')
       ->with($session_id, $session_data)
-      ->will($this->returnValue(FALSE));
+      ->willReturnOnConsecutiveCalls(TRUE, FALSE);
 
     $result = $this->sessionHandler->write($session_id, $session_data);
     $this->assertTrue($result);
diff --git a/web/core/tests/Drupal/Tests/Core/TempStore/PrivateTempStoreTest.php b/web/core/tests/Drupal/Tests/Core/TempStore/PrivateTempStoreTest.php
index 40e1766017..6f233ecabf 100644
--- a/web/core/tests/Drupal/Tests/Core/TempStore/PrivateTempStoreTest.php
+++ b/web/core/tests/Drupal/Tests/Core/TempStore/PrivateTempStoreTest.php
@@ -100,18 +100,18 @@ protected function setUp(): void {
    * @covers ::get
    */
   public function testGet() {
-    $this->keyValue->expects($this->at(0))
+    $this->keyValue->expects($this->exactly(3))
       ->method('get')
-      ->with('1:test_2')
-      ->will($this->returnValue(FALSE));
-    $this->keyValue->expects($this->at(1))
-      ->method('get')
-      ->with('1:test')
-      ->will($this->returnValue($this->ownObject));
-    $this->keyValue->expects($this->at(2))
-      ->method('get')
-      ->with('1:test')
-      ->will($this->returnValue($this->otherObject));
+      ->withConsecutive(
+        ['1:test_2'],
+        ['1:test'],
+        ['1:test'],
+      )
+      ->willReturnOnConsecutiveCalls(
+        FALSE,
+        $this->ownObject,
+        $this->otherObject,
+      );
 
     $this->assertNull($this->tempStore->get('test_2'));
     $this->assertSame($this->ownObject->data, $this->tempStore->get('test'));
@@ -124,17 +124,13 @@ public function testGet() {
    * @covers ::set
    */
   public function testSetWithNoLockAvailable() {
-    $this->lock->expects($this->at(0))
+    $this->lock->expects($this->exactly(2))
       ->method('acquire')
       ->with('1:test')
       ->will($this->returnValue(FALSE));
-    $this->lock->expects($this->at(1))
+    $this->lock->expects($this->once())
       ->method('wait')
       ->with('1:test');
-    $this->lock->expects($this->at(2))
-      ->method('acquire')
-      ->with('1:test')
-      ->will($this->returnValue(FALSE));
 
     $this->keyValue->expects($this->once())
       ->method('getCollectionName');
@@ -172,15 +168,10 @@ public function testSet() {
    * @covers ::getMetadata
    */
   public function testGetMetadata() {
-    $this->keyValue->expects($this->at(0))
-      ->method('get')
-      ->with('1:test')
-      ->will($this->returnValue($this->ownObject));
-
-    $this->keyValue->expects($this->at(1))
+    $this->keyValue->expects($this->exactly(2))
       ->method('get')
       ->with('1:test')
-      ->will($this->returnValue(FALSE));
+      ->willReturnOnConsecutiveCalls($this->ownObject, FALSE);
 
     $metadata = $this->tempStore->getMetadata('test');
     $this->assertInstanceOf(Lock::class, $metadata);
@@ -229,17 +220,13 @@ public function testDeleteWithNoLockAvailable() {
       ->method('get')
       ->with('1:test')
       ->will($this->returnValue($this->ownObject));
-    $this->lock->expects($this->at(0))
+    $this->lock->expects($this->exactly(2))
       ->method('acquire')
       ->with('1:test')
       ->will($this->returnValue(FALSE));
-    $this->lock->expects($this->at(1))
+    $this->lock->expects($this->once())
       ->method('wait')
       ->with('1:test');
-    $this->lock->expects($this->at(2))
-      ->method('acquire')
-      ->with('1:test')
-      ->will($this->returnValue(FALSE));
 
     $this->keyValue->expects($this->once())
       ->method('getCollectionName');
@@ -259,21 +246,21 @@ public function testDelete() {
       ->with('1:test_2')
       ->will($this->returnValue(TRUE));
 
-    $this->keyValue->expects($this->at(0))
+    $this->keyValue->expects($this->exactly(3))
       ->method('get')
-      ->with('1:test_1')
-      ->will($this->returnValue(FALSE));
-    $this->keyValue->expects($this->at(1))
-      ->method('get')
-      ->with('1:test_2')
-      ->will($this->returnValue($this->ownObject));
-    $this->keyValue->expects($this->at(2))
+      ->withConsecutive(
+        ['1:test_1'],
+        ['1:test_2'],
+        ['1:test_3'],
+      )
+      ->willReturnOnConsecutiveCalls(
+        FALSE,
+        $this->ownObject,
+        $this->otherObject,
+      );
+    $this->keyValue->expects($this->once())
       ->method('delete')
       ->with('1:test_2');
-    $this->keyValue->expects($this->at(3))
-      ->method('get')
-      ->with('1:test_3')
-      ->will($this->returnValue($this->otherObject));
 
     $this->assertTrue($this->tempStore->delete('test_1'));
     $this->assertTrue($this->tempStore->delete('test_2'));
diff --git a/web/core/tests/Drupal/Tests/Core/TempStore/SharedTempStoreTest.php b/web/core/tests/Drupal/Tests/Core/TempStore/SharedTempStoreTest.php
index 585fc47ac2..7a4aa9dc69 100644
--- a/web/core/tests/Drupal/Tests/Core/TempStore/SharedTempStoreTest.php
+++ b/web/core/tests/Drupal/Tests/Core/TempStore/SharedTempStoreTest.php
@@ -102,14 +102,16 @@ protected function setUp(): void {
    * @covers ::get
    */
   public function testGet() {
-    $this->keyValue->expects($this->at(0))
-      ->method('get')
-      ->with('test_2')
-      ->will($this->returnValue(FALSE));
-    $this->keyValue->expects($this->at(1))
+    $this->keyValue->expects($this->exactly(2))
       ->method('get')
-      ->with('test')
-      ->will($this->returnValue($this->ownObject));
+      ->withConsecutive(
+        ['test_2'],
+        ['test'],
+      )
+      ->willReturnOnConsecutiveCalls(
+        FALSE,
+        $this->ownObject,
+      );
 
     $this->assertNull($this->tempStore->get('test_2'));
     $this->assertSame($this->ownObject->data, $this->tempStore->get('test'));
@@ -121,18 +123,18 @@ public function testGet() {
    * @covers ::getIfOwner
    */
   public function testGetIfOwner() {
-    $this->keyValue->expects($this->at(0))
-      ->method('get')
-      ->with('test_2')
-      ->will($this->returnValue(FALSE));
-    $this->keyValue->expects($this->at(1))
+    $this->keyValue->expects($this->exactly(3))
       ->method('get')
-      ->with('test')
-      ->will($this->returnValue($this->ownObject));
-    $this->keyValue->expects($this->at(2))
-      ->method('get')
-      ->with('test')
-      ->will($this->returnValue($this->otherObject));
+      ->withConsecutive(
+        ['test_2'],
+        ['test'],
+        ['test'],
+      )
+      ->willReturnOnConsecutiveCalls(
+        FALSE,
+        $this->ownObject,
+        $this->otherObject,
+      );
 
     $this->assertNull($this->tempStore->getIfOwner('test_2'));
     $this->assertSame($this->ownObject->data, $this->tempStore->getIfOwner('test'));
@@ -145,17 +147,13 @@ public function testGetIfOwner() {
    * @covers ::set
    */
   public function testSetWithNoLockAvailable() {
-    $this->lock->expects($this->at(0))
+    $this->lock->expects($this->exactly(2))
       ->method('acquire')
       ->with('test')
       ->will($this->returnValue(FALSE));
-    $this->lock->expects($this->at(1))
+    $this->lock->expects($this->once())
       ->method('wait')
       ->with('test');
-    $this->lock->expects($this->at(2))
-      ->method('acquire')
-      ->with('test')
-      ->will($this->returnValue(FALSE));
 
     $this->keyValue->expects($this->once())
       ->method('getCollectionName');
@@ -262,15 +260,10 @@ public function testSetIfOwner() {
    * @covers ::getMetadata
    */
   public function testGetMetadata() {
-    $this->keyValue->expects($this->at(0))
+    $this->keyValue->expects($this->exactly(2))
       ->method('get')
       ->with('test')
-      ->will($this->returnValue($this->ownObject));
-
-    $this->keyValue->expects($this->at(1))
-      ->method('get')
-      ->with('test')
-      ->will($this->returnValue(FALSE));
+      ->willReturnOnConsecutiveCalls($this->ownObject, FALSE);
 
     $metadata = $this->tempStore->getMetadata('test');
     $this->assertInstanceOf(Lock::class, $metadata);
@@ -310,17 +303,13 @@ public function testDelete() {
    * @covers ::delete
    */
   public function testDeleteWithNoLockAvailable() {
-    $this->lock->expects($this->at(0))
+    $this->lock->expects($this->exactly(2))
       ->method('acquire')
       ->with('test')
       ->will($this->returnValue(FALSE));
-    $this->lock->expects($this->at(1))
+    $this->lock->expects($this->once())
       ->method('wait')
       ->with('test');
-    $this->lock->expects($this->at(2))
-      ->method('acquire')
-      ->with('test')
-      ->will($this->returnValue(FALSE));
 
     $this->keyValue->expects($this->once())
       ->method('getCollectionName');
@@ -340,21 +329,21 @@ public function testDeleteIfOwner() {
       ->with('test_2')
       ->will($this->returnValue(TRUE));
 
-    $this->keyValue->expects($this->at(0))
-      ->method('get')
-      ->with('test_1')
-      ->will($this->returnValue(FALSE));
-    $this->keyValue->expects($this->at(1))
+    $this->keyValue->expects($this->exactly(3))
       ->method('get')
-      ->with('test_2')
-      ->will($this->returnValue($this->ownObject));
-    $this->keyValue->expects($this->at(2))
+      ->withConsecutive(
+        ['test_1'],
+        ['test_2'],
+        ['test_3'],
+      )
+      ->willReturnOnConsecutiveCalls(
+        FALSE,
+        $this->ownObject,
+        $this->otherObject,
+      );
+    $this->keyValue->expects($this->once())
       ->method('delete')
       ->with('test_2');
-    $this->keyValue->expects($this->at(3))
-      ->method('get')
-      ->with('test_3')
-      ->will($this->returnValue($this->otherObject));
 
     $this->assertTrue($this->tempStore->deleteIfOwner('test_1'));
     $this->assertTrue($this->tempStore->deleteIfOwner('test_2'));
diff --git a/web/core/tests/Drupal/Tests/Core/Template/TwigSandboxTest.php b/web/core/tests/Drupal/Tests/Core/Template/TwigSandboxTest.php
index 7f7e8065b9..c7507dc0f7 100644
--- a/web/core/tests/Drupal/Tests/Core/Template/TwigSandboxTest.php
+++ b/web/core/tests/Drupal/Tests/Core/Template/TwigSandboxTest.php
@@ -101,7 +101,7 @@ public function testEntitySafePrefixes() {
       ->method('getEntityType')
       ->willReturn('test');
     $result = $this->twig->render('{{ entity.getEntityType }}', ['entity' => $entity]);
-    $this->assertEquals($result, 'test', 'Sandbox policy allows get* functions to be called.');
+    $this->assertEquals('test', $result, 'Sandbox policy allows get* functions to be called.');
   }
 
   /**
@@ -119,28 +119,28 @@ public function testEntitySafeMethods() {
       ->with('title')
       ->willReturn('test');
     $result = $this->twig->render('{{ entity.get("title") }}', ['entity' => $entity]);
-    $this->assertEquals($result, 'test', 'Sandbox policy allows get() to be called.');
+    $this->assertEquals('test', $result, 'Sandbox policy allows get() to be called.');
 
     $entity = $this->createMock('Drupal\Core\Entity\EntityInterface');
     $entity->expects($this->atLeastOnce())
       ->method('id')
       ->willReturn('1234');
     $result = $this->twig->render('{{ entity.id }}', ['entity' => $entity]);
-    $this->assertEquals($result, '1234', 'Sandbox policy allows get() to be called.');
+    $this->assertEquals('1234', $result, 'Sandbox policy allows get() to be called.');
 
     $entity = $this->createMock('Drupal\Core\Entity\EntityInterface');
     $entity->expects($this->atLeastOnce())
       ->method('label')
       ->willReturn('testing');
     $result = $this->twig->render('{{ entity.label }}', ['entity' => $entity]);
-    $this->assertEquals($result, 'testing', 'Sandbox policy allows get() to be called.');
+    $this->assertEquals('testing', $result, 'Sandbox policy allows get() to be called.');
 
     $entity = $this->createMock('Drupal\Core\Entity\EntityInterface');
     $entity->expects($this->atLeastOnce())
       ->method('bundle')
       ->willReturn('testing');
     $result = $this->twig->render('{{ entity.bundle }}', ['entity' => $entity]);
-    $this->assertEquals($result, 'testing', 'Sandbox policy allows get() to be called.');
+    $this->assertEquals('testing', $result, 'Sandbox policy allows get() to be called.');
   }
 
   /**
@@ -154,7 +154,7 @@ public function testUrlSafeMethods() {
       ->method('toString')
       ->willReturn('http://kittens.cat/are/cute');
     $result = $this->twig->render('{{ url.toString }}', ['url' => $url]);
-    $this->assertEquals($result, 'http://kittens.cat/are/cute', 'Sandbox policy allows toString() to be called.');
+    $this->assertEquals('http://kittens.cat/are/cute', $result, 'Sandbox policy allows toString() to be called.');
   }
 
 }
diff --git a/web/core/tests/Drupal/Tests/Core/Test/JUnitConverterTest.php b/web/core/tests/Drupal/Tests/Core/Test/JUnitConverterTest.php
index 7a001972f6..cfa287e672 100644
--- a/web/core/tests/Drupal/Tests/Core/Test/JUnitConverterTest.php
+++ b/web/core/tests/Drupal/Tests/Core/Test/JUnitConverterTest.php
@@ -30,13 +30,13 @@ public function testXmlToRowsWithErrors() {
 
     $res = JUnitConverter::xmlToRows(1, $phpunit_error_xml);
     $this->assertCount(4, $res, 'All testcases got extracted');
-    $this->assertNotEquals($res[0]['status'], 'pass');
-    $this->assertEquals($res[0]['status'], 'fail');
+    $this->assertNotEquals('pass', $res[0]['status']);
+    $this->assertEquals('fail', $res[0]['status']);
 
     // Test nested testsuites, which appear when you use @dataProvider.
     for ($i = 0; $i < 3; $i++) {
-      $this->assertNotEquals($res[$i + 1]['status'], 'pass');
-      $this->assertEquals($res[$i + 1]['status'], 'fail');
+      $this->assertNotEquals('pass', $res[$i + 1]['status']);
+      $this->assertEquals('fail', $res[$i + 1]['status']);
     }
 
     // Make sure xmlToRows() does not balk if there are no test results.
diff --git a/web/core/tests/Drupal/Tests/Core/Theme/ThemeNegotiatorTest.php b/web/core/tests/Drupal/Tests/Core/Theme/ThemeNegotiatorTest.php
index 4aa373184c..84a5970344 100644
--- a/web/core/tests/Drupal/Tests/Core/Theme/ThemeNegotiatorTest.php
+++ b/web/core/tests/Drupal/Tests/Core/Theme/ThemeNegotiatorTest.php
@@ -153,15 +153,12 @@ public function testDetermineActiveThemeWithAccessCheck() {
       $this->container->set($id, $negotiator);
     }
 
-    $this->themeAccessCheck->expects($this->at(0))
+    $this->themeAccessCheck->expects($this->exactly(2))
       ->method('checkAccess')
-      ->with('example_test')
-      ->will($this->returnValue(FALSE));
-
-    $this->themeAccessCheck->expects($this->at(1))
-      ->method('checkAccess')
-      ->with('example_test2')
-      ->will($this->returnValue(TRUE));
+      ->willReturnMap([
+        ['example_test', FALSE],
+        ['example_test2', TRUE],
+      ]);
 
     $route_match = new RouteMatch('test_route', new Route('/test-route'), [], []);
     $theme = $this->createThemeNegotiator(array_keys($negotiators))->determineActiveTheme($route_match);
diff --git a/web/core/tests/Drupal/Tests/Core/UrlTest.php b/web/core/tests/Drupal/Tests/Core/UrlTest.php
index e52b1049e4..e1a747eb41 100644
--- a/web/core/tests/Drupal/Tests/Core/UrlTest.php
+++ b/web/core/tests/Drupal/Tests/Core/UrlTest.php
@@ -121,27 +121,23 @@ protected function setUp(): void {
    * Tests creating a Url from a request.
    */
   public function testUrlFromRequest() {
-    $this->router->expects($this->at(0))
+    $this->router->expects($this->exactly(3))
       ->method('matchRequest')
-      ->with($this->getRequestConstraint('/node'))
-      ->willReturn([
+      ->withConsecutive(
+        [$this->getRequestConstraint('/node')],
+        [$this->getRequestConstraint('/node/1')],
+        [$this->getRequestConstraint('/node/2/edit')],
+      )
+      ->willReturnOnConsecutiveCalls([
           RouteObjectInterface::ROUTE_NAME => 'view.frontpage.page_1',
           '_raw_variables' => new ParameterBag(),
+        ], [
+          RouteObjectInterface::ROUTE_NAME => 'node_view',
+          '_raw_variables' => new ParameterBag(['node' => '1']),
+        ], [
+          RouteObjectInterface::ROUTE_NAME => 'node_edit',
+          '_raw_variables' => new ParameterBag(['node' => '2']),
         ]);
-    $this->router->expects($this->at(1))
-      ->method('matchRequest')
-      ->with($this->getRequestConstraint('/node/1'))
-      ->willReturn([
-        RouteObjectInterface::ROUTE_NAME => 'node_view',
-        '_raw_variables' => new ParameterBag(['node' => '1']),
-      ]);
-    $this->router->expects($this->at(2))
-      ->method('matchRequest')
-      ->with($this->getRequestConstraint('/node/2/edit'))
-      ->willReturn([
-        RouteObjectInterface::ROUTE_NAME => 'node_edit',
-        '_raw_variables' => new ParameterBag(['node' => '2']),
-      ]);
 
     $urls = [];
     foreach ($this->map as $index => $values) {
diff --git a/web/core/tests/Drupal/Tests/Core/Utility/LinkGeneratorTest.php b/web/core/tests/Drupal/Tests/Core/Utility/LinkGeneratorTest.php
index 2cc2ce6778..f9f1dee711 100644
--- a/web/core/tests/Drupal/Tests/Core/Utility/LinkGeneratorTest.php
+++ b/web/core/tests/Drupal/Tests/Core/Utility/LinkGeneratorTest.php
@@ -419,11 +419,7 @@ public function testGenerateXss() {
    * @see \Drupal\Core\Utility\LinkGenerator::generate()
    */
   public function testGenerateWithHtml() {
-    $this->urlGenerator->expects($this->at(0))
-      ->method('generateFromRoute')
-      ->with('test_route_5', [], $this->defaultOptions)
-      ->willReturn((new GeneratedUrl())->setGeneratedUrl('/test-route-5'));
-    $this->urlGenerator->expects($this->at(1))
+    $this->urlGenerator->expects($this->exactly(2))
       ->method('generateFromRoute')
       ->with('test_route_5', [], $this->defaultOptions)
       ->willReturn((new GeneratedUrl())->setGeneratedUrl('/test-route-5'));
diff --git a/web/core/tests/Drupal/Tests/DocumentElement.php b/web/core/tests/Drupal/Tests/DocumentElement.php
new file mode 100644
index 0000000000..27c4283a24
--- /dev/null
+++ b/web/core/tests/Drupal/Tests/DocumentElement.php
@@ -0,0 +1,84 @@
+<?php
+
+namespace Drupal\Tests;
+
+use Behat\Mink\Driver\BrowserKitDriver;
+use Behat\Mink\Element\TraversableElement;
+
+/**
+ * Document element.
+ *
+ * This is largely a copy of \Behat\Mink\Element\DocumentElement. This fixes the
+ * ::getText() method to remove script tags inside the body element.
+ *
+ * @see \Behat\Mink\Element\DocumentElement
+ * @internal
+ */
+class DocumentElement extends TraversableElement {
+
+  /**
+   * Returns XPath for handled element.
+   *
+   * @return string
+   */
+  public function getXpath() {
+    return '//html';
+  }
+
+  /**
+   * Returns document content.
+   *
+   * @return string
+   */
+  public function getContent() {
+    return trim($this->getDriver()->getContent());
+  }
+
+  /**
+   * Check whether document has specified content.
+   *
+   * @param string $content
+   *
+   * @return bool
+   */
+  public function hasContent($content) {
+    return $this->has('named', ['content', $content]);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getText() {
+    if ($this->getDriver() instanceof BrowserKitDriver) {
+      // Work around https://github.com/minkphp/MinkBrowserKitDriver/issues/153.
+      // To simulate what the user sees, it removes:
+      // - all text inside the head tags
+      // - Drupal settings json.
+      $raw_content = preg_replace([
+        '@<head>(.+?)</head>@si',
+        '@<script type="application/json" data-drupal-selector="drupal-settings-json">([^<]*)</script>@',
+      ], '', $this->getContent());
+      // Filter out all HTML tags, as they are not visible in a normal browser.
+      $text = strip_tags($raw_content);
+      // To preserve BC and match \Behat\Mink\Element\Element::getText() include
+      // the page title.
+      $title_element = $this->find('css', 'title');
+      if ($title_element) {
+        $text = $title_element->getText() . ' ' . $text;
+      }
+      // To match what the user sees and \Behat\Mink\Element\Element::getText()
+      // decode HTML entities.
+      $text = html_entity_decode($text, ENT_QUOTES);
+      // To match \Behat\Mink\Element\Element::getText() remove new lines and
+      // normalize spaces.
+      $text = str_replace("\n", ' ', $text);
+      $text = preg_replace('/ {2,}/', ' ', $text);
+      return trim($text);
+    }
+
+    // If using a real browser fallback to the \Behat\Mink\Element\Element
+    // implementation.
+    return parent::getText();
+  }
+
+}
diff --git a/web/core/tests/bootstrap.php b/web/core/tests/bootstrap.php
index 1d169e8523..4e25592f71 100644
--- a/web/core/tests/bootstrap.php
+++ b/web/core/tests/bootstrap.php
@@ -154,6 +154,7 @@ function drupal_phpunit_populate_class_loader() {
 
 // Do class loader population.
 $loader = drupal_phpunit_populate_class_loader();
+class_alias('\Drupal\Tests\DocumentElement', '\Behat\Mink\Element\DocumentElement', TRUE);
 
 ClassWriter::mutateTestBase($loader);
 
diff --git a/web/core/themes/olivero/css/base/base.css b/web/core/themes/olivero/css/base/base.css
index 15dca4cf48..8077f7b5ba 100644
--- a/web/core/themes/olivero/css/base/base.css
+++ b/web/core/themes/olivero/css/base/base.css
@@ -32,7 +32,7 @@ body {
   background-position: top left /* LTR */
 }
 
-body.js-fixed {
+body.is-fixed {
     position: fixed;
     overflow: hidden;
     width: 100%;
@@ -165,6 +165,6 @@ ul {
   background: #0d77b5;
 }
 
-.js-overlay-active .overlay {
+.is-overlay-active .overlay {
   display: block;
 }
diff --git a/web/core/themes/olivero/css/base/base.pcss.css b/web/core/themes/olivero/css/base/base.pcss.css
index 9e28580f28..cee3edac55 100644
--- a/web/core/themes/olivero/css/base/base.pcss.css
+++ b/web/core/themes/olivero/css/base/base.pcss.css
@@ -26,7 +26,7 @@ body {
   background-image: url("../../images/background.svg");
   background-position: top left; /* LTR */
 
-  &.js-fixed {
+  &.is-fixed {
     position: fixed;
     overflow: hidden;
     width: 100%;
@@ -122,6 +122,6 @@ ul {
   background: var(--color--blue-20);
 }
 
-.js-overlay-active .overlay {
+.is-overlay-active .overlay {
   display: block;
 }
diff --git a/web/core/themes/olivero/css/base/variables.pcss.css b/web/core/themes/olivero/css/base/variables.pcss.css
index 91f331f01e..73936db0da 100644
--- a/web/core/themes/olivero/css/base/variables.pcss.css
+++ b/web/core/themes/olivero/css/base/variables.pcss.css
@@ -118,6 +118,8 @@
   --sp12: calc(12 * var(--sp));
   --color--black: #000; /* Black */
   --color--gray-0: #0d1214; /* Black 1 */
+  --color--gray-5: #0c0d0e;
+  --color--gray-8: #171e23;
   --color--gray-10: #313637; /* Black 2 */
   --color--gray-20: #6e7172; /* Black 3 */
   --color--gray-25: #5d7585; /* Gray Dark */
diff --git a/web/core/themes/olivero/css/components/button.css b/web/core/themes/olivero/css/components/button.css
index 821bb9d100..008818bbb9 100644
--- a/web/core/themes/olivero/css/components/button.css
+++ b/web/core/themes/olivero/css/components/button.css
@@ -153,11 +153,6 @@
     background-color: #d7e1e8;
   }
 
-#drupal-off-canvas input[type="submit"].button {
-    float: left;
-    width: auto;
-  }
-
 .button--icon-back {
   display: inline-flex;
   align-items: center
diff --git a/web/core/themes/olivero/css/components/button.pcss.css b/web/core/themes/olivero/css/components/button.pcss.css
index 19c281d804..c9b838f3fe 100644
--- a/web/core/themes/olivero/css/components/button.pcss.css
+++ b/web/core/themes/olivero/css/components/button.pcss.css
@@ -102,13 +102,6 @@
   }
 }
 
-#drupal-off-canvas input[type="submit"] {
-  &.button {
-    float: left;
-    width: auto;
-  }
-}
-
 .button--icon-back {
   display: inline-flex;
   align-items: center;
diff --git a/web/core/themes/olivero/css/components/comments.css b/web/core/themes/olivero/css/components/comments.css
index ad558c1cfe..6ce64d4e10 100644
--- a/web/core/themes/olivero/css/components/comments.css
+++ b/web/core/themes/olivero/css/components/comments.css
@@ -239,14 +239,6 @@
 }
   }
 
-@media all and (-ms-high-contrast: active), (-ms-high-contrast: none) {
-
-.add-comment__picture,
-.comment__picture {
-    position: relative
-}
-  }
-
 @media (min-width: 43.75rem) {
 
 [dir="ltr"] .indented .comment__picture {
diff --git a/web/core/themes/olivero/css/components/comments.pcss.css b/web/core/themes/olivero/css/components/comments.pcss.css
index 063afbc5bf..11793bb263 100644
--- a/web/core/themes/olivero/css/components/comments.pcss.css
+++ b/web/core/themes/olivero/css/components/comments.pcss.css
@@ -144,10 +144,6 @@
     width: var(--sp3);
     height: var(--sp3);
   }
-
-  @media all and (-ms-high-contrast: active), (-ms-high-contrast: none) {
-    position: relative;
-  }
 }
 
 .indented .comment__picture {
diff --git a/web/core/themes/olivero/css/components/field-image.css b/web/core/themes/olivero/css/components/field-image.css
deleted file mode 100644
index ce1ee665e2..0000000000
--- a/web/core/themes/olivero/css/components/field-image.css
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * DO NOT EDIT THIS FILE.
- * See the following change record for more information,
- * https://www.drupal.org/node/3084859
- * @preserve
- */
-
-/**
- * @file
- * Field image field.
- */
-
-[dir="ltr"] .page-node-type-article .field--name-field-image {
-    margin-left: 0
-}
-
-[dir="rtl"] .page-node-type-article .field--name-field-image {
-    margin-right: 0
-}
-
-[dir="ltr"] .page-node-type-article .field--name-field-image {
-    margin-right: 0
-}
-
-[dir="rtl"] .page-node-type-article .field--name-field-image {
-    margin-left: 0
-}
-
-.page-node-type-article .field--name-field-image {
-    margin-top: 0.5625rem;
-    margin-bottom: 2.25rem
-  }
-
-@media (min-width: 43.75rem) {
-
-[dir="ltr"] .page-node-type-article .field--name-field-image {
-      margin-left: -7.14286vw
-    }
-
-[dir="rtl"] .page-node-type-article .field--name-field-image {
-      margin-right: -7.14286vw
-    }
-
-.page-node-type-article .field--name-field-image {
-      width: calc(100vw - 2.25rem);
-      margin-top: 2.25rem;
-      margin-bottom: 4.5rem
-  }
-    }
-
-@media (min-width: 62.5rem) {
-
-[dir="ltr"] .page-node-type-article .field--name-field-image {
-      margin-left: calc(-7.14286vw - -1.07143px)
-    }
-
-[dir="rtl"] .page-node-type-article .field--name-field-image {
-      margin-right: calc(-7.14286vw - -1.07143px)
-    }
-
-.page-node-type-article .field--name-field-image {
-      width: calc(85.71429vw - 3.05357rem)
-  }
-    }
-
-@media (min-width: 75rem) {
-
-[dir="ltr"] .page-node-type-article .field--name-field-image {
-      margin-left: calc(-7.14286vw - -0.62946rem)
-    }
-
-[dir="rtl"] .page-node-type-article .field--name-field-image {
-      margin-right: calc(-7.14286vw - -0.62946rem)
-    }
-
-.page-node-type-article .field--name-field-image {
-      width: calc(85.71429vw - 9.80357rem)
-  }
-    }
-
-@media (min-width: 90rem) {
-
-[dir="ltr"] .page-node-type-article .field--name-field-image {
-      margin-left: -5.86607rem
-    }
-
-[dir="rtl"] .page-node-type-article .field--name-field-image {
-      margin-right: -5.86607rem
-    }
-
-.page-node-type-article .field--name-field-image {
-      width: 68.14286rem
-  }
-    }
-
-.page-node-type-article {
-
-  /* Ensure that image doesn't overlap sidebar. */
-}
-
-@media (min-width: 62.5rem) {
-
-.page-node-type-article .sidebar-grid .field--name-field-image {
-      width: calc(64.28571vw - 2.85268rem)
-  }
-    }
-
-@media (min-width: 75rem) {
-
-.page-node-type-article .sidebar-grid .field--name-field-image {
-      width: calc(64.28571vw - 7.91518rem)
-  }
-    }
-
-@media (min-width: 81.25rem) {
-
-.page-node-type-article .sidebar-grid .field--name-field-image {
-      width: calc(71.42857vw - 8.54464rem)
-  }
-    }
-
-@media (min-width: 90rem) {
-
-.page-node-type-article .sidebar-grid .field--name-field-image {
-      width: 56.41071rem
-  }
-    }
-
-.page-node-type-article {
-
-  /* Ensure that image doesn't overlap layout builder sections when editing layouts. */
-}
-
-[dir="ltr"] .page-node-type-article .layout-builder .field--name-field-image {
-    margin-left: 0
-}
-
-[dir="rtl"] .page-node-type-article .layout-builder .field--name-field-image {
-    margin-right: 0
-}
-
-[dir="ltr"] .page-node-type-article .layout-builder .field--name-field-image {
-    margin-right: 0
-}
-
-[dir="rtl"] .page-node-type-article .layout-builder .field--name-field-image {
-    margin-left: 0
-}
-
-.page-node-type-article .layout-builder .field--name-field-image {
-    max-width: 100%;
-  }
diff --git a/web/core/themes/olivero/css/components/field-image.pcss.css b/web/core/themes/olivero/css/components/field-image.pcss.css
deleted file mode 100644
index cac8115b83..0000000000
--- a/web/core/themes/olivero/css/components/field-image.pcss.css
+++ /dev/null
@@ -1,62 +0,0 @@
-/**
- * @file
- * Field image field.
- */
-
-@import "../base/variables.pcss.css";
-
-.page-node-type-article {
-  & .field--name-field-image {
-    margin-block-start: var(--sp0-5);
-    margin-block-end: var(--sp2);
-    margin-inline-start: 0;
-    margin-inline-end: 0;
-
-    @media (--grid-md) {
-      width: calc(14 * var(--grid-col-width--md) + 13 * var(--grid-gap--md));
-      margin-block: var(--sp2) var(--sp4);
-      margin-inline-start: calc(-1 * ((var(--grid-col-width--md) + var(--grid-gap--md))));
-    }
-
-    @media (--lg) {
-      width: calc(12 * var(--grid-col-width--lg) + 11 * var(--grid-gap--lg));
-      margin-inline-start: calc(-1 * (var(--grid-col-width--lg) + var(--grid-gap--lg)));
-    }
-
-    @media (--nav) {
-      width: calc(12 * var(--grid-col-width--nav) + 11 * var(--grid-gap--nav));
-      margin-inline-start: calc(-1 * (var(--grid-col-width--nav) + var(--grid-gap--nav)));
-    }
-
-    @media (--grid-max) {
-      width: calc(12 * var(--grid-col-width--max) + 11 * var(--grid-gap--max));
-      margin-inline-start: calc(-1 * (var(--grid-col-width--max) + var(--grid-gap--max)));
-    }
-  }
-
-  /* Ensure that image doesn't overlap sidebar. */
-  & .sidebar-grid .field--name-field-image {
-    @media (--lg) {
-      width: calc(9 * var(--grid-col-width--lg) + 8 * var(--grid-gap--lg));
-    }
-
-    @media (--nav) {
-      width: calc(9 * var(--grid-col-width--nav) + 8 * var(--grid-gap--nav));
-    }
-
-    @media (--xl) {
-      width: calc(10 * var(--grid-col-width--nav) + 9 * var(--grid-gap--nav));
-    }
-
-    @media (--grid-max) {
-      width: calc(10 * var(--grid-col-width--max) + 9 * var(--grid-gap--max));
-    }
-  }
-
-  /* Ensure that image doesn't overlap layout builder sections when editing layouts. */
-  & .layout-builder .field--name-field-image {
-    max-width: 100%;
-    margin-inline-start: 0;
-    margin-inline-end: 0;
-  }
-}
diff --git a/web/core/themes/olivero/css/components/footer.css b/web/core/themes/olivero/css/components/footer.css
index a59f06f8bd..e4e4119f0a 100644
--- a/web/core/themes/olivero/css/components/footer.css
+++ b/web/core/themes/olivero/css/components/footer.css
@@ -13,8 +13,6 @@
 .site-footer {
   position: relative; /* stack above left social bar */
   color: #9ea0a1;
-
-  /* @todo - #0c0d0e and #171e23 aren't currently variables */
   background: linear-gradient(180deg, #0c0d0e 0%, #171e23 100%)
 }
 
diff --git a/web/core/themes/olivero/css/components/footer.pcss.css b/web/core/themes/olivero/css/components/footer.pcss.css
index f425b3f1ea..898a130b2f 100644
--- a/web/core/themes/olivero/css/components/footer.pcss.css
+++ b/web/core/themes/olivero/css/components/footer.pcss.css
@@ -8,9 +8,7 @@
 .site-footer {
   position: relative; /* stack above left social bar */
   color: var(--color--gray-50);
-
-  /* @todo - #0c0d0e and #171e23 aren't currently variables */
-  background: linear-gradient(180deg, #0c0d0e 0%, #171e23 100%);
+  background: linear-gradient(180deg, var(--color--gray-5) 0%, var(--color--gray-8) 100%);
 
   & .menu {
     margin-inline-start: 0;
diff --git a/web/core/themes/olivero/css/components/header-sticky-toggle.css b/web/core/themes/olivero/css/components/header-sticky-toggle.css
index d0ddd15484..1bcb87ec35 100644
--- a/web/core/themes/olivero/css/components/header-sticky-toggle.css
+++ b/web/core/themes/olivero/css/components/header-sticky-toggle.css
@@ -44,7 +44,7 @@
 
 @media (min-width: 75rem) {
 
-body:not(.is-always-mobile-nav) .js-fixed .sticky-header-toggle {
+body:not(.is-always-mobile-nav) .is-fixed .sticky-header-toggle {
     visibility: visible
 }
   }
@@ -124,7 +124,7 @@ body.is-always-mobile-nav .sticky-header-toggle {
       background-color: #fff;
     }
 
-.js-fixed .sticky-header-toggle {
+.is-fixed .sticky-header-toggle {
   cursor: pointer;
   pointer-events: auto;
   opacity: 1;
diff --git a/web/core/themes/olivero/css/components/header-sticky-toggle.pcss.css b/web/core/themes/olivero/css/components/header-sticky-toggle.pcss.css
index 65114a0b4d..04932fb959 100644
--- a/web/core/themes/olivero/css/components/header-sticky-toggle.pcss.css
+++ b/web/core/themes/olivero/css/components/header-sticky-toggle.pcss.css
@@ -34,7 +34,7 @@
   }
 }
 
-body:not(.is-always-mobile-nav) .js-fixed .sticky-header-toggle {
+body:not(.is-always-mobile-nav) .is-fixed .sticky-header-toggle {
   @media (--nav) {
     visibility: visible;
   }
@@ -92,7 +92,7 @@ body.is-always-mobile-nav .sticky-header-toggle {
   }
 }
 
-.js-fixed .sticky-header-toggle {
+.is-fixed .sticky-header-toggle {
   cursor: pointer;
   pointer-events: auto;
   opacity: 1;
diff --git a/web/core/themes/olivero/css/components/messages.css b/web/core/themes/olivero/css/components/messages.css
index e4148fd4fc..ce4039f0f3 100644
--- a/web/core/themes/olivero/css/components/messages.css
+++ b/web/core/themes/olivero/css/components/messages.css
@@ -188,7 +188,6 @@
   cursor: pointer;
   vertical-align: top;
   border: 0;
-  border-radius: 50%;
   background: none;
   -webkit-appearance: none;
   -moz-appearance: none;
@@ -222,7 +221,7 @@
 
 .messages__close:focus {
     outline: 2px solid #53b0eb;
-    outline-offset: 1px;
+    outline-offset: 2px;
   }
 
 .messages__icon svg {
diff --git a/web/core/themes/olivero/css/components/messages.pcss.css b/web/core/themes/olivero/css/components/messages.pcss.css
index 5df84862be..a7de95e7ff 100644
--- a/web/core/themes/olivero/css/components/messages.pcss.css
+++ b/web/core/themes/olivero/css/components/messages.pcss.css
@@ -89,7 +89,6 @@
   cursor: pointer;
   vertical-align: top;
   border: 0;
-  border-radius: 50%;
   background: none;
   appearance: none;
 
@@ -122,7 +121,7 @@
 
   &:focus {
     outline: 2px solid var(--color--blue-70);
-    outline-offset: 1px;
+    outline-offset: 2px;
   }
 }
 
diff --git a/web/core/themes/olivero/css/components/navigation/menu-sidebar.css b/web/core/themes/olivero/css/components/navigation/menu-sidebar.css
new file mode 100644
index 0000000000..15ed877fd9
--- /dev/null
+++ b/web/core/themes/olivero/css/components/navigation/menu-sidebar.css
@@ -0,0 +1,86 @@
+/*
+ * DO NOT EDIT THIS FILE.
+ * See the following change record for more information,
+ * https://www.drupal.org/node/3084859
+ * @preserve
+ */
+
+/**
+ * @file
+ * Styles for menu placed in sidebar region.
+ */
+
+.menu--sidebar {
+  list-style: none
+}
+
+.menu--sidebar .menu {
+    list-style: none;
+  }
+
+.menu--sidebar .menu--level-1 {
+    margin: 0;
+  }
+
+[dir="ltr"] .menu--sidebar .menu__link {
+    padding-left: 0
+}
+
+[dir="rtl"] .menu--sidebar .menu__link {
+    padding-right: 0
+}
+
+[dir="ltr"] .menu--sidebar .menu__link {
+    padding-right: 0
+}
+
+[dir="rtl"] .menu--sidebar .menu__link {
+    padding-left: 0
+}
+
+.menu--sidebar .menu__link {
+    position: relative;
+    display: block;
+    padding-top: 0.84375rem;
+    padding-bottom: 0.84375rem;
+    font-family: "Lora", "georgia", serif;
+    font-size: 1.125rem
+
+    /* Bottom divider line. */
+  }
+
+[dir="ltr"] .menu--sidebar .menu__link:after {
+      left: 0
+}
+
+[dir="rtl"] .menu--sidebar .menu__link:after {
+      right: 0
+}
+
+.menu--sidebar .menu__link:after {
+      position: absolute;
+      bottom: 0;
+      width: 4.5rem;
+      height: 0;
+      content: "";
+      border-top: solid 2px #e7edf1;
+    }
+
+.menu--sidebar .menu__link--link {
+    text-decoration: none;
+    color: #0d1214;
+    font-weight: 600
+  }
+
+.menu--sidebar .menu__link--link:hover {
+      color: #2494db;
+    }
+
+.menu--sidebar {
+
+  /* No bottom divider line for last menu item. */
+}
+
+.menu--sidebar .menu__item--level-1:last-child > .menu__link:last-child:after, .menu--sidebar .menu__item--level-1:last-child > .menu__item--level-2:last-child > .menu__link:last-child:after {
+      content: none;
+    }
diff --git a/web/core/themes/olivero/css/components/sidebar.pcss.css b/web/core/themes/olivero/css/components/navigation/menu-sidebar.pcss.css
similarity index 88%
rename from web/core/themes/olivero/css/components/sidebar.pcss.css
rename to web/core/themes/olivero/css/components/navigation/menu-sidebar.pcss.css
index 4291af2f5b..de077db5ab 100644
--- a/web/core/themes/olivero/css/components/sidebar.pcss.css
+++ b/web/core/themes/olivero/css/components/navigation/menu-sidebar.pcss.css
@@ -1,11 +1,13 @@
 /**
  * @file
- * Styles for sidebar region.
+ * Styles for menu placed in sidebar region.
  */
 
-@import "../base/variables.pcss.css";
+@import "../../base/variables.pcss.css";
+
+.menu--sidebar {
+  list-style: none;
 
-.region--sidebar {
   & .menu {
     list-style: none;
   }
diff --git a/web/core/themes/olivero/css/components/navigation/nav-primary-button.css b/web/core/themes/olivero/css/components/navigation/nav-primary-button.css
index fde8e024d7..5f83bb161d 100644
--- a/web/core/themes/olivero/css/components/navigation/nav-primary-button.css
+++ b/web/core/themes/olivero/css/components/navigation/nav-primary-button.css
@@ -31,7 +31,7 @@
   overflow: hidden;
   width: 2.25rem;
   height: 2.25rem;
-  margin-top: 2px; /* Visually align button with menu link text. */
+  margin-top: 0.5625rem; /* Visually align button with menu link text. */
   padding-top: 0;
   padding-bottom: 0;
   cursor: pointer;
diff --git a/web/core/themes/olivero/css/components/navigation/nav-primary-button.pcss.css b/web/core/themes/olivero/css/components/navigation/nav-primary-button.pcss.css
index 4a330214ba..b31aeb149a 100644
--- a/web/core/themes/olivero/css/components/navigation/nav-primary-button.pcss.css
+++ b/web/core/themes/olivero/css/components/navigation/nav-primary-button.pcss.css
@@ -10,7 +10,7 @@
   overflow: hidden;
   width: var(--sp2);
   height: var(--sp2);
-  margin-block-start: 2px; /* Visually align button with menu link text. */
+  margin-block-start: var(--sp0-5); /* Visually align button with menu link text. */
   padding-block: 0;
   padding-inline-start: 0;
   padding-inline-end: 0;
diff --git a/web/core/themes/olivero/css/components/navigation/nav-primary-wide.css b/web/core/themes/olivero/css/components/navigation/nav-primary-wide.css
index 3fa507b984..7687e06514 100644
--- a/web/core/themes/olivero/css/components/navigation/nav-primary-wide.css
+++ b/web/core/themes/olivero/css/components/navigation/nav-primary-wide.css
@@ -287,7 +287,7 @@ body:not(.is-always-mobile-nav) {
      * little extra room when the toolbar is fixed (and is shorter).
      */
 }
-    body:not(.is-always-mobile-nav) .js-fixed .primary-nav__menu--level-2 {
+    body:not(.is-always-mobile-nav) .is-fixed .primary-nav__menu--level-2 {
       max-height: calc(100vh - 7.875rem);
     }
   }
@@ -305,7 +305,7 @@ body:not(.is-always-mobile-nav) {
         max-height: calc(100vh - 14.8125rem);
       }
 
-      body:not(.is-always-mobile-nav).toolbar-vertical .js-fixed .primary-nav__menu--level-2, body:not(.is-always-mobile-nav).toolbar-horizontal.toolbar-fixed .js-fixed .primary-nav__menu--level-2 {
+      body:not(.is-always-mobile-nav).toolbar-vertical .is-fixed .primary-nav__menu--level-2, body:not(.is-always-mobile-nav).toolbar-horizontal.toolbar-fixed .is-fixed .primary-nav__menu--level-2 {
         max-height: calc(100vh - 10.3125rem);
       }
   body:not(.is-always-mobile-nav) {
@@ -316,7 +316,7 @@ body:not(.is-always-mobile-nav) {
         max-height: calc(100vh - 17.3125rem);
       }
 
-      body:not(.is-always-mobile-nav).toolbar-horizontal.toolbar-fixed.toolbar-tray-open .js-fixed .primary-nav__menu--level-2 {
+      body:not(.is-always-mobile-nav).toolbar-horizontal.toolbar-fixed.toolbar-tray-open .is-fixed .primary-nav__menu--level-2 {
         max-height: calc(100vh - 12.8125rem);
       }
 }
diff --git a/web/core/themes/olivero/css/components/navigation/nav-primary-wide.pcss.css b/web/core/themes/olivero/css/components/navigation/nav-primary-wide.pcss.css
index 36585f8cb7..cecf051616 100644
--- a/web/core/themes/olivero/css/components/navigation/nav-primary-wide.pcss.css
+++ b/web/core/themes/olivero/css/components/navigation/nav-primary-wide.pcss.css
@@ -192,7 +192,7 @@ body:not(.is-always-mobile-nav) {
      * When ensuring that long menus don't overflow viewport, we can give a
      * little extra room when the toolbar is fixed (and is shorter).
      */
-    & .js-fixed .primary-nav__menu--level-2 {
+    & .is-fixed .primary-nav__menu--level-2 {
       max-height: calc(100vh - var(--site-header-height-wide) - var(--sp) + var(--sp4));
     }
   }
@@ -211,7 +211,7 @@ body:not(.is-always-mobile-nav) {
         max-height: calc(100vh - var(--site-header-height-wide) - var(--sp) - var(--toolbar-height));
       }
 
-      & .js-fixed .primary-nav__menu--level-2 {
+      & .is-fixed .primary-nav__menu--level-2 {
         max-height: calc(100vh - var(--site-header-height-wide) - var(--sp) - var(--toolbar-height) + var(--sp4));
       }
     }
@@ -222,7 +222,7 @@ body:not(.is-always-mobile-nav) {
         max-height: calc(100vh - var(--site-header-height-wide) - var(--sp) - var(--toolbar-height) - var(--toolbar-tray-height));
       }
 
-      & .js-fixed .primary-nav__menu--level-2 {
+      & .is-fixed .primary-nav__menu--level-2 {
         max-height: calc(100vh - var(--site-header-height-wide) - var(--sp) - var(--toolbar-height) - var(--toolbar-tray-height) + var(--sp4));
       }
     }
diff --git a/web/core/themes/olivero/css/components/navigation/nav-primary.css b/web/core/themes/olivero/css/components/navigation/nav-primary.css
index 9580666cfb..b36f3cdb59 100644
--- a/web/core/themes/olivero/css/components/navigation/nav-primary.css
+++ b/web/core/themes/olivero/css/components/navigation/nav-primary.css
@@ -134,7 +134,7 @@
 .primary-nav__menu-link--button.primary-nav__menu-link--has-children:before,
     .primary-nav__menu-link--button.primary-nav__menu-link--has-children:after {
       position: absolute;
-      top: 1.25rem;
+      top: 1.625rem; /* Visually align button with menu link text. */
       width: 1.125rem;
       height: 0;
       content: "";
@@ -287,6 +287,8 @@
   overflow: hidden;
   flex-basis: 100%;
   max-height: 0;
+  margin-top: 0;
+  margin-bottom: 0;
   transition: opacity 0.2s, visibility 0.2s, max-height 0.2s;
   opacity: 0
 }
diff --git a/web/core/themes/olivero/css/components/navigation/nav-primary.pcss.css b/web/core/themes/olivero/css/components/navigation/nav-primary.pcss.css
index ece366d18d..a0610f59ec 100644
--- a/web/core/themes/olivero/css/components/navigation/nav-primary.pcss.css
+++ b/web/core/themes/olivero/css/components/navigation/nav-primary.pcss.css
@@ -72,8 +72,8 @@
     &:before,
     &:after {
       position: absolute;
-      inset-block-start: 20px;
       inset-inline-end: 9px;
+      inset-block-start: calc(var(--sp0-5) + 17px); /* Visually align button with menu link text. */
       width: 18px;
       height: 0;
       content: "";
@@ -150,6 +150,7 @@
   overflow: hidden;
   flex-basis: 100%;
   max-height: 0;
+  margin-block: 0;
   margin-inline-start: calc(-1 * var(--sp));
   padding-inline-start: var(--sp2-5);
   transition: opacity 0.2s, visibility 0.2s, max-height 0.2s;
diff --git a/web/core/themes/olivero/css/components/navigation/wide-nav-expand.css b/web/core/themes/olivero/css/components/navigation/wide-nav-expand.css
index 7418808494..b0e0082791 100644
--- a/web/core/themes/olivero/css/components/navigation/wide-nav-expand.css
+++ b/web/core/themes/olivero/css/components/navigation/wide-nav-expand.css
@@ -39,7 +39,7 @@
 
 @media (min-width: 75rem) {
 
-body:not(.is-always-mobile-nav) .js-fixed .wide-nav-expand {
+body:not(.is-always-mobile-nav) .is-fixed .wide-nav-expand {
     visibility: visible
 }
   }
@@ -120,7 +120,7 @@ body.is-always-mobile-nav .wide-nav-expand {
       background-color: currentColor;
     }
 
-.js-fixed .wide-nav-expand__icon {
+.is-fixed .wide-nav-expand__icon {
   opacity: 1;
 }
 
diff --git a/web/core/themes/olivero/css/components/navigation/wide-nav-expand.pcss.css b/web/core/themes/olivero/css/components/navigation/wide-nav-expand.pcss.css
index cec15dba56..d23be8aaea 100644
--- a/web/core/themes/olivero/css/components/navigation/wide-nav-expand.pcss.css
+++ b/web/core/themes/olivero/css/components/navigation/wide-nav-expand.pcss.css
@@ -29,7 +29,7 @@
   }
 }
 
-body:not(.is-always-mobile-nav) .js-fixed .wide-nav-expand {
+body:not(.is-always-mobile-nav) .is-fixed .wide-nav-expand {
   @media (--nav) {
     visibility: visible;
   }
@@ -88,7 +88,7 @@ body.is-always-mobile-nav .wide-nav-expand {
   }
 }
 
-.js-fixed .wide-nav-expand__icon {
+.is-fixed .wide-nav-expand__icon {
   opacity: 1;
 }
 
diff --git a/web/core/themes/olivero/css/components/sidebar.css b/web/core/themes/olivero/css/components/sidebar.css
deleted file mode 100644
index 1d0a040dd8..0000000000
--- a/web/core/themes/olivero/css/components/sidebar.css
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * DO NOT EDIT THIS FILE.
- * See the following change record for more information,
- * https://www.drupal.org/node/3084859
- * @preserve
- */
-
-/**
- * @file
- * Styles for sidebar region.
- */
-
-.region--sidebar .menu {
-    list-style: none;
-  }
-
-.region--sidebar .menu--level-1 {
-    margin: 0;
-  }
-
-[dir="ltr"] .region--sidebar .menu__link {
-    padding-left: 0;
-}
-
-[dir="rtl"] .region--sidebar .menu__link {
-    padding-right: 0;
-}
-
-[dir="ltr"] .region--sidebar .menu__link {
-    padding-right: 0;
-}
-
-[dir="rtl"] .region--sidebar .menu__link {
-    padding-left: 0;
-}
-
-.region--sidebar .menu__link {
-    position: relative;
-    display: block;
-    padding-top: 0.84375rem;
-    padding-bottom: 0.84375rem;
-    font-family: "Lora", "georgia", serif;
-    font-size: 1.125rem
-
-    /* Bottom divider line. */
-  }
-
-[dir="ltr"] .region--sidebar .menu__link:after {
-      left: 0;
-}
-
-[dir="rtl"] .region--sidebar .menu__link:after {
-      right: 0;
-}
-
-.region--sidebar .menu__link:after {
-      position: absolute;
-      bottom: 0;
-      width: 4.5rem;
-      height: 0;
-      content: "";
-      border-top: solid 2px #e7edf1;
-    }
-
-.region--sidebar .menu__link--link {
-    text-decoration: none;
-    color: #0d1214;
-    font-weight: 600
-  }
-
-.region--sidebar .menu__link--link:hover {
-      color: #2494db;
-    }
-
-.region--sidebar {
-
-  /* No bottom divider line for last menu item. */
-}
-
-.region--sidebar .menu__item--level-1:last-child > .menu__link:last-child:after, .region--sidebar .menu__item--level-1:last-child > .menu__item--level-2:last-child > .menu__link:last-child:after {
-      content: none;
-    }
diff --git a/web/core/themes/olivero/css/components/site-header.css b/web/core/themes/olivero/css/components/site-header.css
index 4c4952d1c3..879cdd564d 100644
--- a/web/core/themes/olivero/css/components/site-header.css
+++ b/web/core/themes/olivero/css/components/site-header.css
@@ -40,13 +40,13 @@
 }
 
 @media (min-width: 75rem) {
-      .site-header__fixable.js-fixed:not(.is-expanded) {
+      .site-header__fixable.is-fixed:not(.is-expanded) {
         pointer-events: none;
       }
     }
 
 @media (min-width: 75rem) {
-    body:not(.is-always-mobile-nav) .site-header__fixable.js-fixed {
+    body:not(.is-always-mobile-nav) .site-header__fixable.is-fixed {
       position: fixed;
       z-index: 102; /* Appear above body content that is position: relative */
       top: -4.5rem;
@@ -56,13 +56,13 @@
 
     /* Toolbar is fixed, and tray is either vertical or closed and horizontal. */
   }
-      body:not(.is-always-mobile-nav).toolbar-vertical.toolbar-fixed .site-header__fixable.js-fixed, body:not(.is-always-mobile-nav).toolbar-horizontal.toolbar-fixed .site-header__fixable.js-fixed {
+      body:not(.is-always-mobile-nav).toolbar-vertical.toolbar-fixed .site-header__fixable.is-fixed, body:not(.is-always-mobile-nav).toolbar-horizontal.toolbar-fixed .site-header__fixable.is-fixed {
         top: -2.0625rem;
       }
   body:not(.is-always-mobile-nav) {
     /* Toolbar is fixed, and tray is open and horizontal. */
   }
-    body:not(.is-always-mobile-nav).toolbar-horizontal.toolbar-fixed.toolbar-tray-open .site-header__fixable.js-fixed {
+    body:not(.is-always-mobile-nav).toolbar-horizontal.toolbar-fixed.toolbar-tray-open .site-header__fixable.is-fixed {
       top: 0.4375rem;
     }
 }
@@ -103,7 +103,7 @@ html.js body:not(.is-always-mobile-nav) .site-header__inner {
 
 @media (min-width: 75rem) {
 
-body:not(.is-always-mobile-nav) .site-header__fixable.js-fixed:not(.is-expanded) .site-header__inner {
+body:not(.is-always-mobile-nav) .site-header__fixable.is-fixed:not(.is-expanded) .site-header__inner {
     transform: translateX(-101%); /* LTR */
     opacity: 0
 }
@@ -111,7 +111,7 @@ body:not(.is-always-mobile-nav) .site-header__fixable.js-fixed:not(.is-expanded)
 
 @media (min-width: 75rem) {
 
-[dir="rtl"] body:not(.is-always-mobile-nav) .site-header__fixable.js-fixed:not(.is-expanded) .site-header__inner {
+[dir="rtl"] body:not(.is-always-mobile-nav) .site-header__fixable.is-fixed:not(.is-expanded) .site-header__inner {
     transform: translateX(101%)
 }
   }
diff --git a/web/core/themes/olivero/css/components/site-header.pcss.css b/web/core/themes/olivero/css/components/site-header.pcss.css
index e4307ba237..0a4d69cd2f 100644
--- a/web/core/themes/olivero/css/components/site-header.pcss.css
+++ b/web/core/themes/olivero/css/components/site-header.pcss.css
@@ -29,7 +29,7 @@
   align-items: flex-end;
   transition: all 0.5s;
 
-  &.js-fixed {
+  &.is-fixed {
     @media (--nav) {
       &:not(.is-expanded) {
         pointer-events: none;
@@ -40,7 +40,7 @@
 
 @media (--nav) {
   body:not(.is-always-mobile-nav) {
-    & .site-header__fixable.js-fixed {
+    & .site-header__fixable.is-fixed {
       position: fixed;
       z-index: 102; /* Appear above body content that is position: relative */
       inset-block-start: calc(-1 * var(--sp4));
@@ -50,12 +50,12 @@
     /* Toolbar is fixed, and tray is either vertical or closed and horizontal. */
     &.toolbar-vertical.toolbar-fixed,
     &.toolbar-horizontal.toolbar-fixed {
-      & .site-header__fixable.js-fixed {
+      & .site-header__fixable.is-fixed {
         inset-block-start: calc(var(--toolbar-height) - var(--sp4));
       }
     }
     /* Toolbar is fixed, and tray is open and horizontal. */
-    &.toolbar-horizontal.toolbar-fixed.toolbar-tray-open .site-header__fixable.js-fixed {
+    &.toolbar-horizontal.toolbar-fixed.toolbar-tray-open .site-header__fixable.is-fixed {
       inset-block-start: calc(var(--toolbar-tray-height) + var(--toolbar-height) - var(--sp4));
     }
   }
@@ -90,14 +90,14 @@ html.js body:not(.is-always-mobile-nav) .site-header__inner {
 }
 
 /* Hide the desktop nav when it's fixed and not active. */
-body:not(.is-always-mobile-nav) .site-header__fixable.js-fixed:not(.is-expanded) .site-header__inner {
+body:not(.is-always-mobile-nav) .site-header__fixable.is-fixed:not(.is-expanded) .site-header__inner {
   @media (--nav) {
     transform: translateX(-101%); /* LTR */
     opacity: 0;
   }
 }
 
-[dir="rtl"] body:not(.is-always-mobile-nav) .site-header__fixable.js-fixed:not(.is-expanded) .site-header__inner {
+[dir="rtl"] body:not(.is-always-mobile-nav) .site-header__fixable.is-fixed:not(.is-expanded) .site-header__inner {
   @media (--nav) {
     transform: translateX(101%);
   }
diff --git a/web/core/themes/olivero/css/components/tabs.css b/web/core/themes/olivero/css/components/tabs.css
index 2ccfec6cea..18f516e172 100644
--- a/web/core/themes/olivero/css/components/tabs.css
+++ b/web/core/themes/olivero/css/components/tabs.css
@@ -110,6 +110,7 @@ html:not(.js) .tabs__tab,
 }
   }
 .tabs__link:focus {
+  position: relative;
   outline: solid 3px #2494db;
   outline-offset: -3px;
 }
diff --git a/web/core/themes/olivero/css/components/tabs.pcss.css b/web/core/themes/olivero/css/components/tabs.pcss.css
index 44f3df58a7..5549b5ed19 100644
--- a/web/core/themes/olivero/css/components/tabs.pcss.css
+++ b/web/core/themes/olivero/css/components/tabs.pcss.css
@@ -80,6 +80,7 @@ html:not(.js) .tabs__tab,
 }
 
 .tabs__link:focus {
+  position: relative;
   outline: solid 3px var(--color--blue-50);
   outline-offset: -3px;
 }
diff --git a/web/core/themes/olivero/css/components/tags.css b/web/core/themes/olivero/css/components/tags.css
index 8e25496f23..8920ed2d43 100644
--- a/web/core/themes/olivero/css/components/tags.css
+++ b/web/core/themes/olivero/css/components/tags.css
@@ -29,13 +29,20 @@
   color: #6e7172;
   font-size: 0.875rem;
   font-weight: 600;
-  line-height: 2
+  line-height: 1.6
 }
 
 .field--tags__label:after {
     content: ":";
   }
 
+@media (min-width: 43.75rem) {
+
+.field--tags__label {
+    line-height: 2
+}
+  }
+
 [dir="ltr"] .field--label-inline .field--tags__label {
   padding-left: 0;
 }
diff --git a/web/core/themes/olivero/css/components/tags.pcss.css b/web/core/themes/olivero/css/components/tags.pcss.css
index 233dff9366..2017acb2bf 100644
--- a/web/core/themes/olivero/css/components/tags.pcss.css
+++ b/web/core/themes/olivero/css/components/tags.pcss.css
@@ -17,11 +17,15 @@
   color: var(--color--gray-20);
   font-size: var(--font-size-s);
   font-weight: 600;
-  line-height: 2;
+  line-height: 1.6;
 
   &:after {
     content: ":";
   }
+
+  @media (--md) {
+    line-height: 2;
+  }
 }
 
 .field--label-inline .field--tags__label {
diff --git a/web/core/themes/olivero/css/components/wide-image.css b/web/core/themes/olivero/css/components/wide-image.css
new file mode 100644
index 0000000000..868a0ad1c7
--- /dev/null
+++ b/web/core/themes/olivero/css/components/wide-image.css
@@ -0,0 +1,146 @@
+/*
+ * DO NOT EDIT THIS FILE.
+ * See the following change record for more information,
+ * https://www.drupal.org/node/3084859
+ * @preserve
+ */
+
+/**
+ * @file
+ * Wide image component.
+ */
+
+[dir="ltr"] .wide-image {
+  margin-left: 0
+}
+
+[dir="rtl"] .wide-image {
+  margin-right: 0
+}
+
+[dir="ltr"] .wide-image {
+  margin-right: 0
+}
+
+[dir="rtl"] .wide-image {
+  margin-left: 0
+}
+
+.wide-image {
+  margin-top: 0.5625rem;
+  margin-bottom: 2.25rem
+}
+
+@media (min-width: 43.75rem) {
+
+[dir="ltr"] .wide-image {
+    margin-left: -7.14286vw
+  }
+
+[dir="rtl"] .wide-image {
+    margin-right: -7.14286vw
+  }
+
+.wide-image {
+    width: calc(100vw - 2.25rem);
+    margin-top: 2.25rem;
+    margin-bottom: 4.5rem
+}
+  }
+
+@media (min-width: 62.5rem) {
+
+[dir="ltr"] .wide-image {
+    margin-left: calc(-7.14286vw - -1.07143px)
+  }
+
+[dir="rtl"] .wide-image {
+    margin-right: calc(-7.14286vw - -1.07143px)
+  }
+
+.wide-image {
+    width: calc(85.71429vw - 3.05357rem)
+}
+  }
+
+@media (min-width: 75rem) {
+
+[dir="ltr"] .wide-image {
+    margin-left: calc(-7.14286vw - -0.62946rem)
+  }
+
+[dir="rtl"] .wide-image {
+    margin-right: calc(-7.14286vw - -0.62946rem)
+  }
+
+.wide-image {
+    width: calc(85.71429vw - 9.80357rem)
+}
+  }
+
+@media (min-width: 90rem) {
+
+[dir="ltr"] .wide-image {
+    margin-left: -5.86607rem
+  }
+
+[dir="rtl"] .wide-image {
+    margin-right: -5.86607rem
+  }
+
+.wide-image {
+    width: 68.14286rem
+}
+  }
+
+/* Ensure that image doesn't overlap sidebar. */
+
+@media (min-width: 62.5rem) {
+
+.sidebar-grid .wide-image {
+    width: calc(64.28571vw - 2.85268rem)
+}
+  }
+
+@media (min-width: 75rem) {
+
+.sidebar-grid .wide-image {
+    width: calc(64.28571vw - 7.91518rem)
+}
+  }
+
+@media (min-width: 81.25rem) {
+
+.sidebar-grid .wide-image {
+    width: calc(71.42857vw - 8.54464rem)
+}
+  }
+
+@media (min-width: 90rem) {
+
+.sidebar-grid .wide-image {
+    width: 56.41071rem
+}
+  }
+
+/* Ensure that image doesn't overlap layout builder sections when editing layouts. */
+
+[dir="ltr"] .layout-builder .wide-image {
+  margin-left: 0
+}
+
+[dir="rtl"] .layout-builder .wide-image {
+  margin-right: 0
+}
+
+[dir="ltr"] .layout-builder .wide-image {
+  margin-right: 0
+}
+
+[dir="rtl"] .layout-builder .wide-image {
+  margin-left: 0
+}
+
+.layout-builder .wide-image {
+  max-width: 100%;
+}
diff --git a/web/core/themes/olivero/css/components/wide-image.pcss.css b/web/core/themes/olivero/css/components/wide-image.pcss.css
new file mode 100644
index 0000000000..bcd2df2384
--- /dev/null
+++ b/web/core/themes/olivero/css/components/wide-image.pcss.css
@@ -0,0 +1,60 @@
+/**
+ * @file
+ * Wide image component.
+ */
+
+@import "../base/variables.pcss.css";
+
+.wide-image {
+  margin-block-start: var(--sp0-5);
+  margin-block-end: var(--sp2);
+  margin-inline-start: 0;
+  margin-inline-end: 0;
+
+  @media (--grid-md) {
+    width: calc(14 * var(--grid-col-width--md) + 13 * var(--grid-gap--md));
+    margin-block: var(--sp2) var(--sp4);
+    margin-inline-start: calc(-1 * ((var(--grid-col-width--md) + var(--grid-gap--md))));
+  }
+
+  @media (--lg) {
+    width: calc(12 * var(--grid-col-width--lg) + 11 * var(--grid-gap--lg));
+    margin-inline-start: calc(-1 * (var(--grid-col-width--lg) + var(--grid-gap--lg)));
+  }
+
+  @media (--nav) {
+    width: calc(12 * var(--grid-col-width--nav) + 11 * var(--grid-gap--nav));
+    margin-inline-start: calc(-1 * (var(--grid-col-width--nav) + var(--grid-gap--nav)));
+  }
+
+  @media (--grid-max) {
+    width: calc(12 * var(--grid-col-width--max) + 11 * var(--grid-gap--max));
+    margin-inline-start: calc(-1 * (var(--grid-col-width--max) + var(--grid-gap--max)));
+  }
+}
+
+/* Ensure that image doesn't overlap sidebar. */
+.sidebar-grid .wide-image {
+  @media (--lg) {
+    width: calc(9 * var(--grid-col-width--lg) + 8 * var(--grid-gap--lg));
+  }
+
+  @media (--nav) {
+    width: calc(9 * var(--grid-col-width--nav) + 8 * var(--grid-gap--nav));
+  }
+
+  @media (--xl) {
+    width: calc(10 * var(--grid-col-width--nav) + 9 * var(--grid-gap--nav));
+  }
+
+  @media (--grid-max) {
+    width: calc(10 * var(--grid-col-width--max) + 9 * var(--grid-gap--max));
+  }
+}
+
+/* Ensure that image doesn't overlap layout builder sections when editing layouts. */
+.layout-builder .wide-image {
+  max-width: 100%;
+  margin-inline-start: 0;
+  margin-inline-end: 0;
+}
diff --git a/web/core/themes/olivero/css/layout/grid.css b/web/core/themes/olivero/css/layout/grid.css
index f5614b4616..028cefda82 100644
--- a/web/core/themes/olivero/css/layout/grid.css
+++ b/web/core/themes/olivero/css/layout/grid.css
@@ -45,7 +45,7 @@
 
 .layout--content-narrow .grid-full,
 .layout--pass--content-narrow > * .grid-full {
-    -ms-grid-columns: (minmax(0, 1fr))12];
+    -ms-grid-columns: (minmax(0, 1fr))[ 12 ];
     grid-template-columns: repeat(12, minmax(0, 1fr))
 }
   }
@@ -54,7 +54,7 @@
 
 .layout--content-narrow .grid-full,
 .layout--pass--content-narrow > * .grid-full {
-    -ms-grid-columns: (minmax(0, 1fr))8];
+    -ms-grid-columns: (minmax(0, 1fr))[ 8 ];
     grid-template-columns: repeat(8, minmax(0, 1fr))
 }
   }
@@ -69,7 +69,7 @@
 
 .layout--content-medium .grid-full,
 .layout--pass--content-medium > * .grid-full {
-    -ms-grid-columns: (minmax(0, 1fr))12];
+    -ms-grid-columns: (minmax(0, 1fr))[ 12 ];
     grid-template-columns: repeat(12, minmax(0, 1fr))
 }
   }
@@ -78,7 +78,7 @@
 
 .layout--content-medium .grid-full,
 .layout--pass--content-medium > * .grid-full {
-    -ms-grid-columns: (minmax(0, 1fr))10];
+    -ms-grid-columns: (minmax(0, 1fr))[ 10 ];
     grid-template-columns: repeat(10, minmax(0, 1fr))
 }
   }
diff --git a/web/core/themes/olivero/css/layout/grid.pcss.css b/web/core/themes/olivero/css/layout/grid.pcss.css
index e2f38dc677..7299bfec5e 100644
--- a/web/core/themes/olivero/css/layout/grid.pcss.css
+++ b/web/core/themes/olivero/css/layout/grid.pcss.css
@@ -30,10 +30,12 @@
 .layout--content-narrow .grid-full,
 .layout--pass--content-narrow > * .grid-full {
   @media (--grid-md) {
+    -ms-grid-columns: (minmax(0, 1fr))[ calc(var(--grid-col-count--md) - 2) ];
     grid-template-columns: repeat(calc(var(--grid-col-count--md) - 2), minmax(0, 1fr));
   }
 
   @media (--lg) {
+    -ms-grid-columns: (minmax(0, 1fr))[ calc(var(--grid-col-count--lg) - 6) ];
     grid-template-columns: repeat(calc(var(--grid-col-count--lg) - 6), minmax(0, 1fr));
   }
 }
@@ -46,10 +48,12 @@
 .layout--content-medium .grid-full,
 .layout--pass--content-medium > * .grid-full {
   @media (--grid-md) {
+    -ms-grid-columns: (minmax(0, 1fr))[ calc(var(--grid-col-count--md) - 2) ];
     grid-template-columns: repeat(calc(var(--grid-col-count--md) - 2), minmax(0, 1fr));
   }
 
   @media (--lg) {
+    -ms-grid-columns: (minmax(0, 1fr))[ calc(var(--grid-col-count--md) - 4) ];
     grid-template-columns: repeat(calc(var(--grid-col-count--md) - 4), minmax(0, 1fr));
   }
 }
diff --git a/web/core/themes/olivero/css/layout/layout-content-narrow.css b/web/core/themes/olivero/css/layout/layout-content-narrow.css
index 34b4a0c71c..3d080daf09 100644
--- a/web/core/themes/olivero/css/layout/layout-content-narrow.css
+++ b/web/core/themes/olivero/css/layout/layout-content-narrow.css
@@ -260,3 +260,19 @@
         width: 68.14286rem
     }
       }
+
+/**
+ * <pre> and <blockquote> elements should not break containers and overflow
+ * into sidebar region when present.
+ */
+
+.sidebar-grid .layout--content-narrow.text-content blockquote,
+      .sidebar-grid .layout--content-narrow.text-content pre,
+      .sidebar-grid .layout--content-narrow .text-content blockquote,
+      .sidebar-grid .layout--content-narrow .text-content pre,
+      .sidebar-grid .layout--pass--content-narrow > *.text-content blockquote,
+      .sidebar-grid .layout--pass--content-narrow > *.text-content pre,
+      .sidebar-grid .layout--pass--content-narrow > * .text-content blockquote,
+      .sidebar-grid .layout--pass--content-narrow > * .text-content pre {
+        width: auto;
+      }
diff --git a/web/core/themes/olivero/css/layout/layout-content-narrow.pcss.css b/web/core/themes/olivero/css/layout/layout-content-narrow.pcss.css
index bda45423f2..350250c147 100644
--- a/web/core/themes/olivero/css/layout/layout-content-narrow.pcss.css
+++ b/web/core/themes/olivero/css/layout/layout-content-narrow.pcss.css
@@ -131,3 +131,20 @@
     }
   }
 }
+
+/**
+ * <pre> and <blockquote> elements should not break containers and overflow
+ * into sidebar region when present.
+ */
+.sidebar-grid {
+  & .layout--content-narrow,
+  & .layout--pass--content-narrow > * {
+    &.text-content,
+    & .text-content {
+      & blockquote,
+      & pre {
+        width: auto;
+      }
+    }
+  }
+}
diff --git a/web/core/themes/olivero/css/layout/layout-sidebar.css b/web/core/themes/olivero/css/layout/layout-sidebar.css
index b338e32a40..f71663c480 100644
--- a/web/core/themes/olivero/css/layout/layout-sidebar.css
+++ b/web/core/themes/olivero/css/layout/layout-sidebar.css
@@ -10,7 +10,7 @@
  * Special grid system for sidebar.
  */
 
-.sidebar-grid > .grid-full {
+.sidebar-grid > .site-main {
     -ms-grid-column: 1;
     -ms-grid-column-span: 6;
     grid-column: 1 / 7;
@@ -20,7 +20,7 @@
 
 @media (min-width: 43.75rem) {
 
-.sidebar-grid > .grid-full {
+.sidebar-grid > .site-main {
       -ms-grid-column: 1;
       -ms-grid-column-span: 14;
       grid-column: 1 / 15
@@ -29,105 +29,57 @@
 
 @media (min-width: 62.5rem) {
 
-.sidebar-grid > .grid-full {
-      -ms-grid-columns: (minmax(0, 1fr))[10];
-      grid-template-columns: repeat(10, minmax(0, 1fr));
-      -ms-grid-column: 1;
-      -ms-grid-column-span: 10;
-      grid-column: 1 / 11
+.sidebar-grid > .site-main {
+      display: -ms-grid;
+      display: grid;
+      -ms-grid-columns: (minmax(0, 1fr))[8];
+      grid-template-columns: repeat(8, minmax(0, 1fr));
+      -ms-grid-column: 3;
+      -ms-grid-column-span: 8;
+      grid-column: 3 / 11
   }
 
-      .sidebar-grid > .grid-full .layout--content-narrow,
-      .sidebar-grid > .grid-full .layout--pass--content-narrow > *,
-      .sidebar-grid > .grid-full .layout--content-medium,
-      .sidebar-grid > .grid-full .layout--pass--content-medium > * {
-        -ms-grid-column: 3;
+      .sidebar-grid > .site-main > .region--content-above,
+      .sidebar-grid > .site-main > .region--content {
+        -ms-grid-columns: (minmax(0, 1fr))[8];
+        grid-template-columns: repeat(8, minmax(0, 1fr));
+        -ms-grid-column: 1;
         -ms-grid-column-span: 8;
-        grid-column: 3 / 11
+        grid-column: 1 / 9;
       }
 
-        .sidebar-grid > .grid-full .layout--content-narrow .grid-full, .sidebar-grid > .grid-full .layout--pass--content-narrow > * .grid-full, .sidebar-grid > .grid-full .layout--content-medium .grid-full, .sidebar-grid > .grid-full .layout--pass--content-medium > * .grid-full {
-          -ms-grid-columns: (minmax(0, 1fr))[8];
-          grid-template-columns: repeat(8, minmax(0, 1fr));
-        }
-
-        .sidebar-grid > .grid-full .layout--content-narrow .layout--content-narrow,
-        .sidebar-grid > .grid-full .layout--content-narrow .layout--pass--content-narrow > *,
-        .sidebar-grid > .grid-full .layout--content-narrow .layout--content-medium,
-        .sidebar-grid > .grid-full .layout--content-narrow .layout--pass--content-medium > *,
-        .sidebar-grid > .grid-full .layout--pass--content-narrow > * .layout--content-narrow,
-        .sidebar-grid > .grid-full .layout--pass--content-narrow > * .layout--pass--content-narrow > *,
-        .sidebar-grid > .grid-full .layout--pass--content-narrow > * .layout--content-medium,
-        .sidebar-grid > .grid-full .layout--pass--content-narrow > * .layout--pass--content-medium > *,
-        .sidebar-grid > .grid-full .layout--content-medium .layout--content-narrow,
-        .sidebar-grid > .grid-full .layout--content-medium .layout--pass--content-narrow > *,
-        .sidebar-grid > .grid-full .layout--content-medium .layout--content-medium,
-        .sidebar-grid > .grid-full .layout--content-medium .layout--pass--content-medium > *,
-        .sidebar-grid > .grid-full .layout--pass--content-medium > * .layout--content-narrow,
-        .sidebar-grid > .grid-full .layout--pass--content-medium > * .layout--pass--content-narrow > *,
-        .sidebar-grid > .grid-full .layout--pass--content-medium > * .layout--content-medium,
-        .sidebar-grid > .grid-full .layout--pass--content-medium > * .layout--pass--content-medium > * {
-          -ms-grid-column: 1;
-          -ms-grid-column-span: 8;
-          grid-column: 1 / 9;
-        }
+      .sidebar-grid > .site-main .layout--content-narrow,
+      .sidebar-grid > .site-main .layout--pass--content-narrow > *,
+      .sidebar-grid > .site-main .layout--content-medium,
+      .sidebar-grid > .site-main .layout--pass--content-medium > * {
+        -ms-grid-column: 1;
+        -ms-grid-column-span: 8;
+        grid-column: 1 / 9;
+      }
     }
 
-@media (min-width: 43.75rem) {
-
-.sidebar-grid .layout--content-narrow,
-  .sidebar-grid .layout--pass--content-narrow > *,
-  .sidebar-grid .layout--content-medium,
-  .sidebar-grid .layout--pass--content-medium > * {
-      -ms-grid-column: 2;
-      -ms-grid-column-span: 12;
-      grid-column: 2 / 14
+.sidebar-grid .region--sidebar {
+    -ms-grid-row: 2;
+    -ms-grid-column: 1;
+    -ms-grid-column-span: 6;
+    grid-column: 1 / 7
   }
-    }
 
-@media (min-width: 62.5rem) {
+@media (min-width: 43.75rem) {
 
-.sidebar-grid .layout--content-narrow,
-  .sidebar-grid .layout--pass--content-narrow > *,
-  .sidebar-grid .layout--content-medium,
-  .sidebar-grid .layout--pass--content-medium > * {
+.sidebar-grid .region--sidebar {
       -ms-grid-column: 3;
-      -ms-grid-column-span: 8;
-      grid-column: 3 / 11
+      -ms-grid-column-span: 10;
+      grid-column: 3 / 13
   }
     }
 
-.region--sidebar {
-  -ms-grid-row: 2;
-  -ms-grid-column: 1;
-  -ms-grid-column-span: 6;
-  grid-column: 1 / 7
-}
-
-@media (min-width: 43.75rem) {
-
-.region--sidebar {
-    -ms-grid-column: 3;
-    -ms-grid-column-span: 10;
-    grid-column: 3 / 13
-}
-  }
-
 @media (min-width: 62.5rem) {
 
-.region--sidebar {
-    -ms-grid-row: 1;
-    -ms-grid-column: 11;
-    -ms-grid-column-span: 4;
-    grid-column: 11 / 15
-}
-  }
-
-@media (min-width: 81.25rem) {
-
-.region--sidebar {
-    -ms-grid-column: 12;
-    -ms-grid-column-span: 3;
-    grid-column: 12 / 15
-}
+.sidebar-grid .region--sidebar {
+      -ms-grid-row: 1;
+      -ms-grid-column: 12;
+      -ms-grid-column-span: 3;
+      grid-column: 12 / 15
   }
+    }
diff --git a/web/core/themes/olivero/css/layout/layout-sidebar.pcss.css b/web/core/themes/olivero/css/layout/layout-sidebar.pcss.css
index 2745272a96..2a28d01e59 100644
--- a/web/core/themes/olivero/css/layout/layout-sidebar.pcss.css
+++ b/web/core/themes/olivero/css/layout/layout-sidebar.pcss.css
@@ -6,7 +6,7 @@
 @import "../base/variables.pcss.css";
 
 .sidebar-grid {
-  & > .grid-full {
+  & > .site-main {
     grid-column: 1 / 7;
     align-self: flex-start;
     -ms-grid-row-align: start;
@@ -16,57 +16,36 @@
     }
 
     @media (--lg) {
-      grid-template-columns: repeat(10, minmax(0, 1fr));
-      grid-column: 1 / 11;
+      display: grid;
+      grid-template-columns: repeat(8, minmax(0, 1fr));
+      grid-column: 3 / 11;
+
+      & > .region--content-above,
+      & > .region--content {
+        grid-template-columns: repeat(8, minmax(0, 1fr));
+        grid-column: 1 / 9;
+      }
 
       & .layout--content-narrow,
       & .layout--pass--content-narrow > *,
       & .layout--content-medium,
       & .layout--pass--content-medium > * {
-        grid-column: 3 / 11;
-
-        & .grid-full {
-          grid-template-columns: repeat(8, minmax(0, 1fr));
-        }
-
-        & .layout--content-narrow,
-        & .layout--pass--content-narrow > *,
-        & .layout--content-medium,
-        & .layout--pass--content-medium > * {
-          grid-column: 1 / 9;
-        }
+        grid-column: 1 / 9;
       }
     }
   }
 
-  & .layout--content-narrow,
-  & .layout--pass--content-narrow > *,
-  & .layout--content-medium,
-  & .layout--pass--content-medium > * {
+  & .region--sidebar {
+    -ms-grid-row: 2;
+    grid-column: 1 / 7;
+
     @media (--grid-md) {
-      grid-column: 2 / 14;
+      grid-column: 3 / 13;
     }
 
     @media (--lg) {
-      grid-column: 3 / 11;
+      -ms-grid-row: 1;
+      grid-column: 12 / 15;
     }
   }
 }
-
-.region--sidebar {
-  -ms-grid-row: 2;
-  grid-column: 1 / 7;
-
-  @media (--grid-md) {
-    grid-column: 3 / 13;
-  }
-
-  @media (--lg) {
-    -ms-grid-row: 1;
-    grid-column: 11 / 15;
-  }
-
-  @media (--xl) {
-    grid-column: 12 / 15;
-  }
-}
diff --git a/web/core/themes/olivero/css/layout/social-bar.css b/web/core/themes/olivero/css/layout/social-bar.css
index 939438b2c4..33c4b41ea8 100644
--- a/web/core/themes/olivero/css/layout/social-bar.css
+++ b/web/core/themes/olivero/css/layout/social-bar.css
@@ -67,15 +67,15 @@
     padding-bottom: 5.625rem
 }
 
-    [dir="ltr"] .social-bar__inner.js-fixed {
+    [dir="ltr"] .social-bar__inner.is-fixed {
       left: 0
 }
 
-    [dir="rtl"] .social-bar__inner.js-fixed {
+    [dir="rtl"] .social-bar__inner.is-fixed {
       right: 0
 }
 
-    .social-bar__inner.js-fixed {
+    .social-bar__inner.is-fixed {
       position: fixed;
       top: 6.75rem;
       height: calc(100vh - 6.75rem);
diff --git a/web/core/themes/olivero/css/layout/social-bar.pcss.css b/web/core/themes/olivero/css/layout/social-bar.pcss.css
index 2cd4b6b9de..858b3e78f9 100644
--- a/web/core/themes/olivero/css/layout/social-bar.pcss.css
+++ b/web/core/themes/olivero/css/layout/social-bar.pcss.css
@@ -27,7 +27,7 @@
     padding-inline-start: 0;
     padding-inline-end: 0;
 
-    &.js-fixed {
+    &.is-fixed {
       position: fixed;
       inset-block-start: var(--sp6);
       inset-inline-start: 0;
diff --git a/web/core/themes/olivero/js/checkbox.es6.js b/web/core/themes/olivero/js/checkbox.es6.js
index 26243e7f74..2114e28a42 100644
--- a/web/core/themes/olivero/js/checkbox.es6.js
+++ b/web/core/themes/olivero/js/checkbox.es6.js
@@ -1,6 +1,6 @@
 /**
  * @file
- * Theme override for checkbox.
+ * Customization of checkbox.
  */
 
 ((Drupal) => {
diff --git a/web/core/themes/olivero/js/comments.es6.js b/web/core/themes/olivero/js/comments.es6.js
index 5117d8e32c..1e70ee9e86 100644
--- a/web/core/themes/olivero/js/comments.es6.js
+++ b/web/core/themes/olivero/js/comments.es6.js
@@ -1,39 +1,63 @@
 /**
  * @file
- * Comments.
+ * Customization of comments.
  */
 
-((Drupal) => {
-  const indentedComments = document.querySelectorAll('.comments .indented');
+((Drupal, once) => {
+  /**
+   * Initialize show/hide button for the comments.
+   *
+   * @param {Element} comments
+   *   The comment wrapper element.
+   */
+  function init(comments) {
+    comments
+      .querySelectorAll('[data-drupal-selector="comment"]')
+      .forEach((comment) => {
+        if (
+          comment.nextElementSibling != null &&
+          comment.nextElementSibling.matches('.indented')
+        ) {
+          comment.classList.add('has-children');
+        }
+      });
 
-  document.querySelectorAll('.comment').forEach((comment) => {
-    if (
-      comment.nextElementSibling != null &&
-      comment.nextElementSibling.matches('.indented')
-    ) {
-      comment.classList.add('has-children');
-    }
-  });
+    comments.querySelectorAll('.indented').forEach((commentGroup) => {
+      const showHideWrapper = document.createElement('div');
+      showHideWrapper.setAttribute('class', 'show-hide-wrapper');
 
-  indentedComments.forEach((commentGroup) => {
-    const showHideWrapper = document.createElement('div');
-    showHideWrapper.setAttribute('class', 'show-hide-wrapper');
+      const toggleCommentsBtn = document.createElement('button');
+      toggleCommentsBtn.setAttribute('type', 'button');
+      toggleCommentsBtn.setAttribute('aria-expanded', 'true');
+      toggleCommentsBtn.setAttribute('class', 'show-hide-btn');
+      toggleCommentsBtn.innerText = Drupal.t('Replies');
 
-    const toggleCommentsBtn = document.createElement('button');
-    toggleCommentsBtn.setAttribute('type', 'button');
-    toggleCommentsBtn.setAttribute('aria-expanded', 'true');
-    toggleCommentsBtn.setAttribute('class', 'show-hide-btn');
-    toggleCommentsBtn.innerText = Drupal.t('Replies');
+      commentGroup.parentNode.insertBefore(showHideWrapper, commentGroup);
+      showHideWrapper.appendChild(toggleCommentsBtn);
 
-    commentGroup.parentNode.insertBefore(showHideWrapper, commentGroup);
-    showHideWrapper.appendChild(toggleCommentsBtn);
+      toggleCommentsBtn.addEventListener('click', (e) => {
+        commentGroup.classList.toggle('hidden');
+        e.currentTarget.setAttribute(
+          'aria-expanded',
+          commentGroup.classList.contains('hidden') ? 'false' : 'true',
+        );
+      });
+    });
+  }
 
-    toggleCommentsBtn.addEventListener('click', (e) => {
-      commentGroup.classList.toggle('hidden');
-      e.currentTarget.setAttribute(
-        'aria-expanded',
-        commentGroup.classList.contains('hidden') ? 'false' : 'true',
+  /**
+   * Attaches the comment behavior to comments.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attaches the show/hide behavior for indented comments.
+   */
+  Drupal.behaviors.comments = {
+    attach(context) {
+      once('comments', '[data-drupal-selector="comments"]', context).forEach(
+        init,
       );
-    });
-  });
-})(Drupal);
+    },
+  };
+})(Drupal, once);
diff --git a/web/core/themes/olivero/js/comments.js b/web/core/themes/olivero/js/comments.js
index 8376ad2929..ba0af97b61 100644
--- a/web/core/themes/olivero/js/comments.js
+++ b/web/core/themes/olivero/js/comments.js
@@ -5,26 +5,33 @@
 * @preserve
 **/
 
-(function (Drupal) {
-  var indentedComments = document.querySelectorAll('.comments .indented');
-  document.querySelectorAll('.comment').forEach(function (comment) {
-    if (comment.nextElementSibling != null && comment.nextElementSibling.matches('.indented')) {
-      comment.classList.add('has-children');
-    }
-  });
-  indentedComments.forEach(function (commentGroup) {
-    var showHideWrapper = document.createElement('div');
-    showHideWrapper.setAttribute('class', 'show-hide-wrapper');
-    var toggleCommentsBtn = document.createElement('button');
-    toggleCommentsBtn.setAttribute('type', 'button');
-    toggleCommentsBtn.setAttribute('aria-expanded', 'true');
-    toggleCommentsBtn.setAttribute('class', 'show-hide-btn');
-    toggleCommentsBtn.innerText = Drupal.t('Replies');
-    commentGroup.parentNode.insertBefore(showHideWrapper, commentGroup);
-    showHideWrapper.appendChild(toggleCommentsBtn);
-    toggleCommentsBtn.addEventListener('click', function (e) {
-      commentGroup.classList.toggle('hidden');
-      e.currentTarget.setAttribute('aria-expanded', commentGroup.classList.contains('hidden') ? 'false' : 'true');
+(function (Drupal, once) {
+  function init(comments) {
+    comments.querySelectorAll('[data-drupal-selector="comment"]').forEach(function (comment) {
+      if (comment.nextElementSibling != null && comment.nextElementSibling.matches('.indented')) {
+        comment.classList.add('has-children');
+      }
+    });
+    comments.querySelectorAll('.indented').forEach(function (commentGroup) {
+      var showHideWrapper = document.createElement('div');
+      showHideWrapper.setAttribute('class', 'show-hide-wrapper');
+      var toggleCommentsBtn = document.createElement('button');
+      toggleCommentsBtn.setAttribute('type', 'button');
+      toggleCommentsBtn.setAttribute('aria-expanded', 'true');
+      toggleCommentsBtn.setAttribute('class', 'show-hide-btn');
+      toggleCommentsBtn.innerText = Drupal.t('Replies');
+      commentGroup.parentNode.insertBefore(showHideWrapper, commentGroup);
+      showHideWrapper.appendChild(toggleCommentsBtn);
+      toggleCommentsBtn.addEventListener('click', function (e) {
+        commentGroup.classList.toggle('hidden');
+        e.currentTarget.setAttribute('aria-expanded', commentGroup.classList.contains('hidden') ? 'false' : 'true');
+      });
     });
-  });
-})(Drupal);
\ No newline at end of file
+  }
+
+  Drupal.behaviors.comments = {
+    attach: function attach(context) {
+      once('comments', '[data-drupal-selector="comments"]', context).forEach(init);
+    }
+  };
+})(Drupal, once);
\ No newline at end of file
diff --git a/web/core/themes/olivero/js/messages.es6.js b/web/core/themes/olivero/js/messages.es6.js
index 7b63bb3c5e..5a3ae83ab5 100644
--- a/web/core/themes/olivero/js/messages.es6.js
+++ b/web/core/themes/olivero/js/messages.es6.js
@@ -1,11 +1,11 @@
 /**
  * @file
- * Messages.
+ * Customization of messages.
  */
 
 ((Drupal, once) => {
   /**
-   * Adds close button to the message.
+   * Adds a close button to the message.
    *
    * @param {object} message
    *   The message object.
@@ -108,7 +108,12 @@
   };
 
   /**
-   * Getting messages from context.
+   * Get messages from context.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attaches the close button behavior for messages.
    */
   Drupal.behaviors.messages = {
     attach(context) {
diff --git a/web/core/themes/olivero/js/navigation.es6.js b/web/core/themes/olivero/js/navigation.es6.js
index 3160027aca..7d36d17ee6 100644
--- a/web/core/themes/olivero/js/navigation.es6.js
+++ b/web/core/themes/olivero/js/navigation.es6.js
@@ -1,8 +1,15 @@
+/**
+ * @file
+ * Customization of navigation.
+ */
+
 ((Drupal, once, tabbable) => {
   /**
    * Checks if navWrapper contains "is-active" class.
-   * @param {object} navWrapper
+   *
+   * @param {Element} navWrapper
    *   Header navigation.
+   *
    * @return {boolean}
    *   True if navWrapper contains "is-active" class, false if not.
    */
@@ -12,6 +19,7 @@
 
   /**
    * Opens or closes the header navigation.
+   *
    * @param {object} props
    *   Navigation props.
    * @param {boolean} state
@@ -22,18 +30,19 @@
     props.navButton.setAttribute('aria-expanded', value);
 
     if (value) {
-      props.body.classList.add('js-overlay-active');
-      props.body.classList.add('js-fixed');
+      props.body.classList.add('is-overlay-active');
+      props.body.classList.add('is-fixed');
       props.navWrapper.classList.add('is-active');
     } else {
-      props.body.classList.remove('js-overlay-active');
-      props.body.classList.remove('js-fixed');
+      props.body.classList.remove('is-overlay-active');
+      props.body.classList.remove('is-fixed');
       props.navWrapper.classList.remove('is-active');
     }
   }
 
   /**
-   * Init function for header navigation.
+   * Initialize the header navigation.
+   *
    * @param {object} props
    *   Navigation props.
    */
@@ -45,9 +54,9 @@
       toggleNav(props, !isNavOpen(props.navWrapper));
     });
 
-    // Closes any open sub navigation first, then close header navigation.
+    // Close any open sub-navigation first, then close the header navigation.
     document.addEventListener('keyup', (e) => {
-      if (e.key === 'Escape') {
+      if (e.key === 'Escape' || e.key === 'Esc') {
         if (props.olivero.areAnySubNavsOpen()) {
           props.olivero.closeAllSubNav();
         } else {
@@ -94,12 +103,11 @@
     });
 
     // Remove overlays when browser is resized and desktop nav appears.
-    // @todo Use core/drupal.debounce library to throttle when we move into theming.
     window.addEventListener('resize', () => {
       if (props.olivero.isDesktopNav()) {
         toggleNav(props, false);
-        props.body.classList.remove('js-overlay-active');
-        props.body.classList.remove('js-fixed');
+        props.body.classList.remove('is-overlay-active');
+        props.body.classList.remove('is-fixed');
       }
 
       // Ensure that all sub-navigation menus close when the browser is resized.
@@ -108,24 +116,29 @@
   }
 
   /**
-   * Initialize the navigation JS.
+   * Initialize the navigation.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Attach context and settings for navigation.
    */
   Drupal.behaviors.oliveroNavigation = {
     attach(context) {
       const headerId = 'header';
-      const header = once(
-        'olivero-navigation',
-        `#${headerId}`,
-        context,
-      ).shift();
+      const header = once('navigation', `#${headerId}`, context).shift();
       const navWrapperId = 'header-nav';
 
       if (header) {
-        const navWrapper = header.querySelector('#header-nav');
+        const navWrapper = header.querySelector(`#${navWrapperId}`);
         const { olivero } = Drupal;
-        const navButton = context.querySelector('.mobile-nav-button');
+        const navButton = context.querySelector(
+          '[data-drupal-selector="mobile-nav-button"]',
+        );
         const body = context.querySelector('body');
-        const overlay = context.querySelector('.overlay');
+        const overlay = context.querySelector(
+          '[data-drupal-selector="overlay"]',
+        );
 
         init({
           olivero,
diff --git a/web/core/themes/olivero/js/navigation.js b/web/core/themes/olivero/js/navigation.js
index 9662a556f0..ccfadcf82d 100644
--- a/web/core/themes/olivero/js/navigation.js
+++ b/web/core/themes/olivero/js/navigation.js
@@ -15,12 +15,12 @@
     props.navButton.setAttribute('aria-expanded', value);
 
     if (value) {
-      props.body.classList.add('js-overlay-active');
-      props.body.classList.add('js-fixed');
+      props.body.classList.add('is-overlay-active');
+      props.body.classList.add('is-fixed');
       props.navWrapper.classList.add('is-active');
     } else {
-      props.body.classList.remove('js-overlay-active');
-      props.body.classList.remove('js-fixed');
+      props.body.classList.remove('is-overlay-active');
+      props.body.classList.remove('is-fixed');
       props.navWrapper.classList.remove('is-active');
     }
   }
@@ -32,7 +32,7 @@
       toggleNav(props, !isNavOpen(props.navWrapper));
     });
     document.addEventListener('keyup', function (e) {
-      if (e.key === 'Escape') {
+      if (e.key === 'Escape' || e.key === 'Esc') {
         if (props.olivero.areAnySubNavsOpen()) {
           props.olivero.closeAllSubNav();
         } else {
@@ -67,8 +67,8 @@
     window.addEventListener('resize', function () {
       if (props.olivero.isDesktopNav()) {
         toggleNav(props, false);
-        props.body.classList.remove('js-overlay-active');
-        props.body.classList.remove('js-fixed');
+        props.body.classList.remove('is-overlay-active');
+        props.body.classList.remove('is-fixed');
       }
 
       Drupal.olivero.closeAllSubNav();
@@ -78,15 +78,15 @@
   Drupal.behaviors.oliveroNavigation = {
     attach: function attach(context) {
       var headerId = 'header';
-      var header = once('olivero-navigation', "#".concat(headerId), context).shift();
+      var header = once('navigation', "#".concat(headerId), context).shift();
       var navWrapperId = 'header-nav';
 
       if (header) {
-        var navWrapper = header.querySelector('#header-nav');
+        var navWrapper = header.querySelector("#".concat(navWrapperId));
         var olivero = Drupal.olivero;
-        var navButton = context.querySelector('.mobile-nav-button');
+        var navButton = context.querySelector('[data-drupal-selector="mobile-nav-button"]');
         var body = context.querySelector('body');
-        var overlay = context.querySelector('.overlay');
+        var overlay = context.querySelector('[data-drupal-selector="overlay"]');
         init({
           olivero: olivero,
           header: header,
diff --git a/web/core/themes/olivero/js/scripts.es6.js b/web/core/themes/olivero/js/scripts.es6.js
index d9572dddc4..7c80dac3f5 100644
--- a/web/core/themes/olivero/js/scripts.es6.js
+++ b/web/core/themes/olivero/js/scripts.es6.js
@@ -1,3 +1,11 @@
+/**
+ * @file
+ * Controls the visibility of desktop navigation.
+ *
+ * Shows and hides the desktop navigation based on scroll position and controls
+ * the functionality of the button that shows/hides the navigation.
+ */
+
 /* eslint-disable no-inner-declarations */
 ((Drupal) => {
   /**
@@ -7,6 +15,12 @@
    */
   Drupal.olivero = {};
 
+  /**
+   * Checks if the mobile navigation button is visible.
+   *
+   * @return {boolean}
+   *   True if navButtons is hidden, false if not.
+   */
   function isDesktopNav() {
     const navButtons = document.querySelector(
       '[data-drupal-selector="mobile-buttons"]',
@@ -25,6 +39,12 @@
     '[data-drupal-selector="site-header-fixable"]',
   );
 
+  /**
+   * Checks if the sticky header is enabled.
+   *
+   * @return {boolean}
+   *   True if sticky header is enabled, false if not.
+   */
   function stickyHeaderIsEnabled() {
     return stickyHeaderToggleButton.getAttribute('aria-checked') === 'true';
   }
@@ -33,7 +53,8 @@
    * Save the current sticky header expanded state to localStorage, and set
    * it to expire after two weeks.
    *
-   * @param {boolean} expandedState - Current state of the sticky header button.
+   * @param {boolean} expandedState
+   *   Current state of the sticky header button.
    */
   function setStickyHeaderStorage(expandedState) {
     const now = new Date();
@@ -52,7 +73,8 @@
    * Toggle the state of the sticky header between always pinned and
    * only pinned when scrolled to the top of the viewport.
    *
-   * @param {boolean} pinnedState - State to change the sticky header to.
+   * @param {boolean} pinnedState
+   *   State to change the sticky header to.
    */
   function toggleStickyHeaderState(pinnedState) {
     if (isDesktopNav()) {
@@ -70,7 +92,8 @@
   /**
    * Return the sticky header's stored state from localStorage.
    *
-   * @return {boolean} Stored state of the sticky header.
+   * @return {boolean}
+   *   Stored state of the sticky header.
    */
   function getStickyHeaderStorage() {
     const stickyHeaderState = localStorage.getItem(
@@ -91,7 +114,8 @@
     return item.value;
   }
 
-  // Only enable scroll effects if the browser supports Intersection Observer.
+  // Only enable scroll interactivity if the browser supports Intersection
+  // Observer.
   // @see https://github.com/w3c/IntersectionObserver/blob/master/polyfill/intersection-observer.js#L19-L21
   if (
     'IntersectionObserver' in window &&
@@ -106,16 +130,22 @@
       if (!isDesktopNav()) return;
 
       entries.forEach((entry) => {
-        // FF doesn't seem to support entry.isIntersecting properly,
+        // Firefox doesn't seem to support entry.isIntersecting properly,
         // so we check the intersectionRatio.
         if (entry.intersectionRatio < 1) {
-          fixableElements.forEach((el) => el.classList.add('js-fixed'));
+          fixableElements.forEach((el) => el.classList.add('is-fixed'));
         } else {
-          fixableElements.forEach((el) => el.classList.remove('js-fixed'));
+          fixableElements.forEach((el) => el.classList.remove('is-fixed'));
         }
       });
     }
 
+    /**
+     * Gets the root margin by checking for various toolbar classes.
+     *
+     * @return {string}
+     *   Root margin for the Intersection Observer options object.
+     */
     function getRootMargin() {
       let rootMarginTop = 72;
       const { body } = document;
@@ -134,6 +164,9 @@
       return `${rootMarginTop}px 0px 0px 0px`;
     }
 
+    /**
+     * Monitor the navigation position.
+     */
     function monitorNavPosition() {
       const primaryNav = document.querySelector(
         '[data-drupal-selector="site-header"]',
diff --git a/web/core/themes/olivero/js/scripts.js b/web/core/themes/olivero/js/scripts.js
index 3dd146860e..7e7d0093c7 100644
--- a/web/core/themes/olivero/js/scripts.js
+++ b/web/core/themes/olivero/js/scripts.js
@@ -65,11 +65,11 @@
       entries.forEach(function (entry) {
         if (entry.intersectionRatio < 1) {
           fixableElements.forEach(function (el) {
-            return el.classList.add('js-fixed');
+            return el.classList.add('is-fixed');
           });
         } else {
           fixableElements.forEach(function (el) {
-            return el.classList.remove('js-fixed');
+            return el.classList.remove('is-fixed');
           });
         }
       });
diff --git a/web/core/themes/olivero/js/search.es6.js b/web/core/themes/olivero/js/search.es6.js
index 6f27225cda..0a5c41afae 100644
--- a/web/core/themes/olivero/js/search.es6.js
+++ b/web/core/themes/olivero/js/search.es6.js
@@ -1,3 +1,8 @@
+/**
+ * @file
+ * Customization of search.
+ */
+
 ((Drupal) => {
   const searchWideButton = document.querySelector(
     '[data-drupal-selector="block-search-wide-button"]',
@@ -6,11 +11,20 @@
     '[data-drupal-selector="block-search-wide-wrapper"]',
   );
 
+  /**
+   * Determine if search is visible.
+   *
+   * @return {boolean}
+   *   True if the search wrapper contains "is-active" class, false if not.
+   */
   function searchIsVisible() {
     return searchWideWrapper.classList.contains('is-active');
   }
   Drupal.olivero.searchIsVisible = searchIsVisible;
 
+  /**
+   * Set focus for the search input element.
+   */
   function handleFocus() {
     if (searchIsVisible()) {
       searchWideWrapper.querySelector('input[type="search"]').focus();
@@ -19,6 +33,12 @@
     }
   }
 
+  /**
+   * Toggle search functionality visibility.
+   *
+   * @param {boolean} visibility
+   *   True if we want to show the form, false if we want to hide it.
+   */
   function toggleSearchVisibility(visibility) {
     searchWideButton.setAttribute('aria-expanded', visibility === true);
     searchWideWrapper.addEventListener('transitionend', handleFocus, {
diff --git a/web/core/themes/olivero/js/second-level-navigation.es6.js b/web/core/themes/olivero/js/second-level-navigation.es6.js
index 4383eed760..70d1c51ebf 100644
--- a/web/core/themes/olivero/js/second-level-navigation.es6.js
+++ b/web/core/themes/olivero/js/second-level-navigation.es6.js
@@ -1,18 +1,25 @@
+/**
+ * @file
+ * Provides functionality for second level submenu navigation.
+ */
+
 ((Drupal) => {
   const { isDesktopNav } = Drupal.olivero;
   const secondLevelNavMenus = document.querySelectorAll(
-    '.primary-nav__menu-item--has-children',
+    '[data-drupal-selector="primary-nav-menu-item-has-children"]',
   );
 
   /**
    * Shows and hides the specified menu item's second level submenu.
    *
-   * @param {element} topLevelMenuItem - the <li> element that is the container for the menu and submenus.
-   * @param {boolean} [toState] - Optional state where we want the submenu to end up.
+   * @param {Element} topLevelMenuItem
+   *   The <li> element that is the container for the menu and submenus.
+   * @param {boolean} [toState]
+   *   Optional state where we want the submenu to end up.
    */
   function toggleSubNav(topLevelMenuItem, toState) {
     const buttonSelector =
-      '.primary-nav__button-toggle, .primary-nav__menu-link--button';
+      '[data-drupal-selector="primary-nav-submenu-toggle-button"]';
     const button = topLevelMenuItem.querySelector(buttonSelector);
     const state =
       toState !== undefined
@@ -27,29 +34,29 @@
             'aria-expanded',
             'false',
           );
-          el.querySelector('.primary-nav__menu--level-2').classList.remove(
-            'is-active-menu-parent',
-          );
-          el.querySelector('.primary-nav__menu-🥕').classList.remove(
-            'is-active-menu-parent',
-          );
+          el.querySelector(
+            '[data-drupal-selector="primary-nav-menu--level-2"]',
+          ).classList.remove('is-active-menu-parent');
+          el.querySelector(
+            '[data-drupal-selector="primary-nav-menu-🥕"]',
+          ).classList.remove('is-active-menu-parent');
         });
       }
       button.setAttribute('aria-expanded', 'true');
       topLevelMenuItem
-        .querySelector('.primary-nav__menu--level-2')
+        .querySelector('[data-drupal-selector="primary-nav-menu--level-2"]')
         .classList.add('is-active-menu-parent');
       topLevelMenuItem
-        .querySelector('.primary-nav__menu-🥕')
+        .querySelector('[data-drupal-selector="primary-nav-menu-🥕"]')
         .classList.add('is-active-menu-parent');
     } else {
       button.setAttribute('aria-expanded', 'false');
       topLevelMenuItem.classList.remove('is-touch-event');
       topLevelMenuItem
-        .querySelector('.primary-nav__menu--level-2')
+        .querySelector('[data-drupal-selector="primary-nav-menu--level-2"]')
         .classList.remove('is-active-menu-parent');
       topLevelMenuItem
-        .querySelector('.primary-nav__menu-🥕')
+        .querySelector('[data-drupal-selector="primary-nav-menu-🥕"]')
         .classList.remove('is-active-menu-parent');
     }
   }
@@ -60,14 +67,15 @@
    * Sets a timeout and closes current desktop navigation submenu if it
    * does not contain the focused element.
    *
-   * @param {object} e - event object
+   * @param {Event} e
+   *   The event object.
    */
   function handleBlur(e) {
     if (!Drupal.olivero.isDesktopNav()) return;
 
     setTimeout(() => {
       const menuParentItem = e.target.closest(
-        '.primary-nav__menu-item--has-children',
+        '[data-drupal-selector="primary-nav-menu-item-has-children"]',
       );
       if (!menuParentItem.contains(document.activeElement)) {
         toggleSubNav(menuParentItem, false);
@@ -78,7 +86,7 @@
   // Add event listeners onto each sub navigation parent and button.
   secondLevelNavMenus.forEach((el) => {
     const button = el.querySelector(
-      '.primary-nav__button-toggle, .primary-nav__menu-link--button',
+      '[data-drupal-selector="primary-nav-submenu-toggle-button"]',
     );
 
     button.removeAttribute('aria-hidden');
@@ -136,7 +144,7 @@
       // Return focus to the toggle button if the submenu contains focus.
       if (el.contains(document.activeElement)) {
         el.querySelector(
-          '.primary-nav__button-toggle, .primary-nav__menu-link--button',
+          '[data-drupal-selector="primary-nav-submenu-toggle-button"]',
         ).focus();
       }
       toggleSubNav(el, false);
@@ -147,14 +155,16 @@
 
   /**
    * Checks if any sub navigation items are currently active.
-   * @return {boolean} If sub nav is currently open.
+   *
+   * @return {boolean}
+   *   If sub navigation is currently open.
    */
   function areAnySubNavsOpen() {
     let subNavsAreOpen = false;
 
     secondLevelNavMenus.forEach((el) => {
       const button = el.querySelector(
-        '.primary-nav__button-toggle, .primary-nav__menu-link--button',
+        '[data-drupal-selector="primary-nav-submenu-toggle-button"]',
       );
       const state = button.getAttribute('aria-expanded') === 'true';
 
@@ -168,7 +178,7 @@
 
   Drupal.olivero.areAnySubNavsOpen = areAnySubNavsOpen;
 
-  // Ensure that desktop submenus close when ESC key is pressed.
+  // Ensure that desktop submenus close when escape key is pressed.
   document.addEventListener('keyup', (e) => {
     if (e.key === 'Escape' || e.key === 'Esc') {
       if (isDesktopNav()) closeAllSubNav();
@@ -181,7 +191,9 @@
     (e) => {
       if (
         areAnySubNavsOpen() &&
-        !e.target.matches('.header-nav, .header-nav *')
+        !e.target.matches(
+          '[data-drupal-selector="header-nav"], [data-drupal-selector="header-nav"] *',
+        )
       ) {
         closeAllSubNav();
       }
diff --git a/web/core/themes/olivero/js/second-level-navigation.js b/web/core/themes/olivero/js/second-level-navigation.js
index 517c159d03..8575af8ec5 100644
--- a/web/core/themes/olivero/js/second-level-navigation.js
+++ b/web/core/themes/olivero/js/second-level-navigation.js
@@ -7,10 +7,10 @@
 
 (function (Drupal) {
   var isDesktopNav = Drupal.olivero.isDesktopNav;
-  var secondLevelNavMenus = document.querySelectorAll('.primary-nav__menu-item--has-children');
+  var secondLevelNavMenus = document.querySelectorAll('[data-drupal-selector="primary-nav-menu-item-has-children"]');
 
   function toggleSubNav(topLevelMenuItem, toState) {
-    var buttonSelector = '.primary-nav__button-toggle, .primary-nav__menu-link--button';
+    var buttonSelector = '[data-drupal-selector="primary-nav-submenu-toggle-button"]';
     var button = topLevelMenuItem.querySelector(buttonSelector);
     var state = toState !== undefined ? toState : button.getAttribute('aria-expanded') !== 'true';
 
@@ -18,19 +18,19 @@
       if (isDesktopNav()) {
         secondLevelNavMenus.forEach(function (el) {
           el.querySelector(buttonSelector).setAttribute('aria-expanded', 'false');
-          el.querySelector('.primary-nav__menu--level-2').classList.remove('is-active-menu-parent');
-          el.querySelector('.primary-nav__menu-🥕').classList.remove('is-active-menu-parent');
+          el.querySelector('[data-drupal-selector="primary-nav-menu--level-2"]').classList.remove('is-active-menu-parent');
+          el.querySelector('[data-drupal-selector="primary-nav-menu-🥕"]').classList.remove('is-active-menu-parent');
         });
       }
 
       button.setAttribute('aria-expanded', 'true');
-      topLevelMenuItem.querySelector('.primary-nav__menu--level-2').classList.add('is-active-menu-parent');
-      topLevelMenuItem.querySelector('.primary-nav__menu-🥕').classList.add('is-active-menu-parent');
+      topLevelMenuItem.querySelector('[data-drupal-selector="primary-nav-menu--level-2"]').classList.add('is-active-menu-parent');
+      topLevelMenuItem.querySelector('[data-drupal-selector="primary-nav-menu-🥕"]').classList.add('is-active-menu-parent');
     } else {
       button.setAttribute('aria-expanded', 'false');
       topLevelMenuItem.classList.remove('is-touch-event');
-      topLevelMenuItem.querySelector('.primary-nav__menu--level-2').classList.remove('is-active-menu-parent');
-      topLevelMenuItem.querySelector('.primary-nav__menu-🥕').classList.remove('is-active-menu-parent');
+      topLevelMenuItem.querySelector('[data-drupal-selector="primary-nav-menu--level-2"]').classList.remove('is-active-menu-parent');
+      topLevelMenuItem.querySelector('[data-drupal-selector="primary-nav-menu-🥕"]').classList.remove('is-active-menu-parent');
     }
   }
 
@@ -39,7 +39,7 @@
   function handleBlur(e) {
     if (!Drupal.olivero.isDesktopNav()) return;
     setTimeout(function () {
-      var menuParentItem = e.target.closest('.primary-nav__menu-item--has-children');
+      var menuParentItem = e.target.closest('[data-drupal-selector="primary-nav-menu-item-has-children"]');
 
       if (!menuParentItem.contains(document.activeElement)) {
         toggleSubNav(menuParentItem, false);
@@ -48,7 +48,7 @@
   }
 
   secondLevelNavMenus.forEach(function (el) {
-    var button = el.querySelector('.primary-nav__button-toggle, .primary-nav__menu-link--button');
+    var button = el.querySelector('[data-drupal-selector="primary-nav-submenu-toggle-button"]');
     button.removeAttribute('aria-hidden');
     button.removeAttribute('tabindex');
     el.addEventListener('touchstart', function () {
@@ -81,7 +81,7 @@
   function closeAllSubNav() {
     secondLevelNavMenus.forEach(function (el) {
       if (el.contains(document.activeElement)) {
-        el.querySelector('.primary-nav__button-toggle, .primary-nav__menu-link--button').focus();
+        el.querySelector('[data-drupal-selector="primary-nav-submenu-toggle-button"]').focus();
       }
 
       toggleSubNav(el, false);
@@ -93,7 +93,7 @@
   function areAnySubNavsOpen() {
     var subNavsAreOpen = false;
     secondLevelNavMenus.forEach(function (el) {
-      var button = el.querySelector('.primary-nav__button-toggle, .primary-nav__menu-link--button');
+      var button = el.querySelector('[data-drupal-selector="primary-nav-submenu-toggle-button"]');
       var state = button.getAttribute('aria-expanded') === 'true';
 
       if (state) {
@@ -110,7 +110,7 @@
     }
   });
   document.addEventListener('touchstart', function (e) {
-    if (areAnySubNavsOpen() && !e.target.matches('.header-nav, .header-nav *')) {
+    if (areAnySubNavsOpen() && !e.target.matches('[data-drupal-selector="header-nav"], [data-drupal-selector="header-nav"] *')) {
       closeAllSubNav();
     }
   }, {
diff --git a/web/core/themes/olivero/js/tabs.es6.js b/web/core/themes/olivero/js/tabs.es6.js
index b5c1232aa8..309cdb87f4 100644
--- a/web/core/themes/olivero/js/tabs.es6.js
+++ b/web/core/themes/olivero/js/tabs.es6.js
@@ -1,13 +1,36 @@
+/**
+ * @file
+ * Provides interactivity for showing and hiding the tabs at mobile widths.
+ */
+
 ((Drupal, once) => {
+  /**
+   * Initialize the tabs.
+   *
+   * @param {HTMLElement} el
+   *   The DOM element containing the tabs.
+   */
   function init(el) {
     const tabs = el.querySelector('.tabs');
     const expandedClass = 'is-expanded';
     const activeTab = tabs.querySelector('.is-active');
 
+    /**
+     * Determines if tabs are expanded for mobile layouts.
+     *
+     * @return {boolean}
+     *   Whether the tabs trigger element is expanded.
+     */
     function isTabsMobileLayout() {
       return tabs.querySelector('.tabs__trigger').clientHeight > 0;
     }
 
+    /**
+     * Controls tab visibility on click events.
+     *
+     * @param {Event} e
+     *   The event object.
+     */
     function handleTriggerClick(e) {
       if (!tabs.classList.contains(expandedClass)) {
         e.currentTarget.setAttribute('aria-expanded', 'true');
@@ -30,6 +53,14 @@
       .addEventListener('click', handleTriggerClick);
   }
 
+  /**
+   * Initialize the tabs.
+   *
+   * @type {Drupal~behavior}
+   *
+   * @prop {Drupal~behaviorAttach} attach
+   *   Display tabs according to the screen width.
+   */
   Drupal.behaviors.tabs = {
     attach(context) {
       once('olivero-tabs', '[data-drupal-nav-tabs]', context).forEach(init);
diff --git a/web/core/themes/olivero/olivero.libraries.yml b/web/core/themes/olivero/olivero.libraries.yml
index 45fea8603b..812983ad11 100644
--- a/web/core/themes/olivero/olivero.libraries.yml
+++ b/web/core/themes/olivero/olivero.libraries.yml
@@ -27,7 +27,6 @@ global-styling:
       css/components/container-inline.module.css: {}
       css/components/fieldset.css: {}
       css/components/field.css: {}
-      css/components/field-image.css: {}
       css/components/form.css: {}
       css/components/form-boolean.css: {}
       css/components/form-text.css: {}
@@ -54,6 +53,7 @@ global-styling:
       css/components/table.css: {}
       css/components/text-content.css: {}
       css/components/tabledrag.css: {}
+      css/components/wide-image.css: {}
 
   js:
     js/checkbox.js: {}
@@ -134,10 +134,13 @@ messages:
   js:
     js/messages.js: {}
 
-sidebar:
+menu-sidebar:
   css:
     component:
-      css/components/sidebar.css: {}
+      css/components/navigation/menu-sidebar.css: {}
+
+sidebar:
+  css:
     layout:
       css/layout/layout-sidebar.css: {}
 
diff --git a/web/core/themes/olivero/olivero.theme b/web/core/themes/olivero/olivero.theme
index f4bccd71f3..d0617dee55 100644
--- a/web/core/themes/olivero/olivero.theme
+++ b/web/core/themes/olivero/olivero.theme
@@ -120,26 +120,23 @@ function olivero_preprocess_block(&$variables) {
       ->load($variables['elements']['#id']);
     if ($block) {
       $region = $block->getRegion();
-      if ($region == 'primary_menu') {
-        if ($variables['base_plugin_id'] === 'system_menu_block') {
-          $variables['content']['#attributes']['region'] = $region;
+
+      if ($variables['base_plugin_id'] === 'system_menu_block') {
+        $variables['content']['#attributes']['region'] = $region;
+        if ($region === 'sidebar') {
+          $variables['#attached']['library'][] = 'olivero/menu-sidebar';
         }
-        elseif ($variables['base_plugin_id'] === 'search_form_block') {
-          // Attaching library for search block if present at primary menu
-          // region.
+      }
+
+      if ($variables['base_plugin_id'] === 'search_form_block') {
+        if ($region === 'primary_menu') {
           $variables['#attached']['library'][] = 'olivero/search-narrow';
+          $variables['content']['actions']['submit']['#theme_wrappers'] = ['input__submit__header_search'];
+        }
+        elseif ($region === 'secondary_menu') {
+          $variables['#attached']['library'][] = 'olivero/search-wide';
+          $variables['content']['actions']['submit']['#theme_wrappers'] = ['input__submit__header_search'];
         }
-      }
-      elseif ($region === 'secondary_menu' && $variables['base_plugin_id'] === 'system_menu_block') {
-        $variables['content']['#attributes']['region'] = $region;
-      }
-      elseif ($region === 'secondary_menu' && $variables['base_plugin_id'] === 'search_form_block') {
-        // Attaching library for search block if present at secondary menu
-        // region.
-        $variables['#attached']['library'][] = 'olivero/search-wide';
-      }
-      if ($variables['base_plugin_id'] === 'search_form_block' && in_array($region, ['primary_menu', 'secondary_menu'], TRUE)) {
-        $variables['content']['actions']['submit']['#theme_wrappers'] = ['input__submit__header_search'];
       }
     }
   }
@@ -166,6 +163,18 @@ function olivero_theme_suggestions_menu_alter(&$suggestions, array $variables) {
   }
 }
 
+/**
+ * Implements hook_preprocess_HOOK().
+ */
+function olivero_preprocess_menu(&$variables) {
+  if (isset($variables['attributes']['region'])) {
+    if ($variables['attributes']['region'] === 'sidebar') {
+      $variables['attributes']['class'][] = 'menu--sidebar';
+    }
+    unset($variables['attributes']['region']);
+  }
+}
+
 /**
  * Implements hook_theme_suggestions_HOOK_alter() for form templates.
  */
@@ -348,6 +357,10 @@ function olivero_preprocess_field(&$variables) {
   if (in_array($variables['field_type'], $rich_field_types, TRUE)) {
     $variables['attributes']['class'][] = 'text-content';
   }
+
+  if ($variables['field_type'] == 'image' && $variables['element']['#view_mode'] == 'full' && !$variables["element"]["#is_multiple"]) {
+    $variables['attributes']['class'][] = 'wide-image';
+  }
 }
 
 /**
diff --git a/web/core/themes/olivero/templates/content/comment.html.twig b/web/core/themes/olivero/templates/content/comment.html.twig
index 01dacdefd3..21aa81fff8 100644
--- a/web/core/themes/olivero/templates/content/comment.html.twig
+++ b/web/core/themes/olivero/templates/content/comment.html.twig
@@ -67,7 +67,6 @@
 {%
   set classes = [
     'comment',
-    'js-comment',
     not parent_comment ? 'comment--level-1',
     status != 'published' ? 'comment--' ~ status,
     comment.owner.anonymous ? 'by-anonymous',
@@ -75,7 +74,7 @@
   ]
 %}
 {{ attach_library('olivero/comments') }}
-<article {{ attributes.addClass(classes).setAttribute('role', 'article') }}>
+<article {{ attributes.addClass(classes).setAttribute('role', 'article').setAttribute('data-drupal-selector', 'comment') }}>
   <div class="comment__picture-wrapper">
     <div class="comment__picture">
       {{ user_picture }}
diff --git a/web/core/themes/olivero/templates/field/field--comment.html.twig b/web/core/themes/olivero/templates/field/field--comment.html.twig
index b0ffc250d1..9f27682067 100644
--- a/web/core/themes/olivero/templates/field/field--comment.html.twig
+++ b/web/core/themes/olivero/templates/field/field--comment.html.twig
@@ -29,7 +29,7 @@
 #}
 
 {{ attach_library('olivero/comments') }}
-<section{{ attributes.addClass('comments') }}>
+<section{{ attributes.setAttribute('data-drupal-selector', 'comments').addClass('comments') }}>
 
   {% if comments and not label_hidden %}
     {{ title_prefix }}
diff --git a/web/core/themes/olivero/templates/layout/page.html.twig b/web/core/themes/olivero/templates/layout/page.html.twig
index 33cfc1fa8d..9be3b5cf8b 100644
--- a/web/core/themes/olivero/templates/layout/page.html.twig
+++ b/web/core/themes/olivero/templates/layout/page.html.twig
@@ -72,7 +72,7 @@
 
               {% if page.primary_menu or page.secondary_menu %}
                 <div class="mobile-buttons" data-drupal-selector="mobile-buttons">
-                  <button class="mobile-nav-button" aria-label="{{ 'Toggle Main Menu'|t }}" aria-controls="header-nav" aria-expanded="false">
+                  <button class="mobile-nav-button" data-drupal-selector="mobile-nav-button" aria-label="{{ 'Toggle Main Menu'|t }}" aria-controls="header-nav" aria-expanded="false">
                     <span class="mobile-nav-button__label">{{ 'Menu'|t }}</span>
                     <span class="mobile-nav-button__icon"></span>
                   </button>
@@ -91,24 +91,31 @@
 
     <div id="main-wrapper" class="layout-main-wrapper layout-container">
       <div id="main" class="layout-main">
-        <main id="content" class="main-content " role="main">
+        <div class="main-content">
           <a id="main-content" tabindex="-1"></a>
           {{ page.hero }}
           <div class="main-content__container container">
             {{ page.highlighted }}
             {{ page.breadcrumb }}
-            {{ page.content_above }}
+
             {% if page.sidebar %}
               <div class="sidebar-grid grid-full">
-                {{ page.content }}
+                <main role="main" class="site-main ie11-autorow">
+                  {{ page.content_above }}
+                  {{ page.content }}
+                </main>
+
                 {{ page.sidebar }}
               </div>
             {% else %}
-              {{ page.content }}
+              <main role="main">
+                {{ page.content_above }}
+                {{ page.content }}
+              </main>
             {% endif %}
             {{ page.content_below }}
           </div>
-        </main>
+        </div>
         <div class="social-bar">
           {{ page.social }}
         </div>
@@ -122,7 +129,7 @@
       </div>
     </footer>
 
-    <div class="overlay"></div>
+    <div class="overlay" data-drupal-selector="overlay"></div>
 
   </div>
 </div>
diff --git a/web/core/themes/olivero/templates/layout/region--content-below.html.twig b/web/core/themes/olivero/templates/layout/region--content-below.html.twig
index 90da7002ca..c0f9ed29e5 100644
--- a/web/core/themes/olivero/templates/layout/region--content-below.html.twig
+++ b/web/core/themes/olivero/templates/layout/region--content-below.html.twig
@@ -22,7 +22,7 @@
 {{ attach_library('olivero/content-below') }}
 
 {% if content %}
-  <aside{{ attributes.addClass(classes) }}>
+  <div{{ attributes.addClass(classes) }}>
     {{ content }}
-  </aside>
+  </div>
 {% endif %}
diff --git a/web/core/themes/olivero/templates/layout/region--content.html.twig b/web/core/themes/olivero/templates/layout/region--content.html.twig
index cd770e624b..42c2ec00fc 100644
--- a/web/core/themes/olivero/templates/layout/region--content.html.twig
+++ b/web/core/themes/olivero/templates/layout/region--content.html.twig
@@ -24,7 +24,7 @@
 %}
 
 {% if content %}
-  <div{{ attributes.addClass(classes) }}>
+  <div{{ attributes.addClass(classes) }} id="content">
     {{ content }}
   </div>
 {% endif %}
diff --git a/web/core/themes/olivero/templates/layout/region--social.html.twig b/web/core/themes/olivero/templates/layout/region--social.html.twig
index 95744ffc86..6f3cf69740 100644
--- a/web/core/themes/olivero/templates/layout/region--social.html.twig
+++ b/web/core/themes/olivero/templates/layout/region--social.html.twig
@@ -13,8 +13,8 @@
  */
 #}
 
-<aside class="social-bar__inner" data-drupal-selector="social-bar-inner">
+<div class="social-bar__inner fixable">
   <div class="rotate">
     {{ content }}
   </div>
-</aside>
+</div>
diff --git a/web/core/themes/olivero/templates/navigation/menu--primary-menu.html.twig b/web/core/themes/olivero/templates/navigation/menu--primary-menu.html.twig
index 99470be983..0e48692578 100644
--- a/web/core/themes/olivero/templates/navigation/menu--primary-menu.html.twig
+++ b/web/core/themes/olivero/templates/navigation/menu--primary-menu.html.twig
@@ -31,6 +31,7 @@
 
 {% macro menu_links(items, attributes, menu_level) %}
   {% set primary_nav_level = 'primary-nav__menu--level-' ~ (menu_level + 1) %}
+  {% set drupal_selector_primary_nav_level = 'primary-nav-menu--level-' ~ (menu_level + 1) %}
   {% import _self as menus %}
   {% if items %}
 
@@ -39,10 +40,10 @@
       has the overflow:hidden CSS rule applied.
     #}
     {% if menu_level == 1 %}
-      <span class="primary-nav__menu-🥕"></span>
+      <span data-drupal-selector="primary-nav-menu-🥕" class="primary-nav__menu-🥕"></span>
     {% endif %}
 
-    <ul {{ attributes.addClass('primary-nav__menu', primary_nav_level) }}>
+    <ul {{ attributes.addClass('primary-nav__menu', primary_nav_level).setAttribute('data-drupal-selector', drupal_selector_primary_nav_level) }}>
       {% set attributes = attributes.removeClass(primary_nav_level) %}
       {% for item in items %}
 
@@ -72,7 +73,7 @@
           ]
         %}
 
-        <li{{ item.attributes.addClass(item_classes) }}>
+        <li{{ item.attributes.addClass(item_classes).setAttribute('data-drupal-selector', item.below ? 'primary-nav-menu-item-has-children' : false) }}>
           {#
             A unique HTML ID should be used, but that isn't available through
             Twig yet, so the |clean_id filter is used for now.
@@ -84,7 +85,11 @@
           {% endset %}
 
           {% if menu_item_type == 'link' or menu_item_type == 'nolink' %}
-            {{ link(menu_item_type == 'link' ? link_title : item.title, item.url, { 'class': link_classes }) }}
+            {{ link(menu_item_type == 'link' ? link_title : item.title, item.url, {
+              'class': link_classes,
+              'data-drupal-selector': 'primary-nav-menu-link-has-children',
+              })
+            }}
 
             {% if item.below %}
               {#
@@ -92,7 +97,17 @@
                 but still visible in non-JS environments so that chevron can indicate presence of
                 drop menu).
               #}
-              <button class="primary-nav__button-toggle" aria-controls="{{ aria_id }}" aria-expanded="false" aria-hidden="true" tabindex="-1">
+              {%
+                set toggle_button_attributes = create_attribute({
+                  'class': 'primary-nav__button-toggle',
+                  'data-drupal-selector': 'primary-nav-submenu-toggle-button',
+                  'aria-controls': aria_id,
+                  'aria-expanded': 'false',
+                  'aria-hidden': 'true',
+                  'tabindex': '-1',
+                })
+              %}
+              <button{{ toggle_button_attributes }}>
                 <span class="visually-hidden">{{ '@title sub-navigation'|t({'@title': item.title}) }}</span>
                 <span class="icon--menu-toggle"></span>
               </button>
@@ -106,6 +121,7 @@
               'class': link_classes,
               'aria-controls': item.below ? aria_id : false,
               'aria-expanded': item.below ? 'false' : false,
+              'data-drupal-selector': item.below ? 'primary-nav-submenu-toggle-button' : false,
               })
             }}
 
-- 
GitLab