Loading
test: #3618216 Add kernel and functional tests for the Admin theme
What the MR adds
Kernel tests (core/themes/default_admin/tests/src/Kernel/)
| Class | Cases | Covers |
|---|---|---|
PreprocessHooksTest |
84 | Every #[Hook('preprocess_*')] method in PreprocessHooks: admin blocks, block, datetime wrapper, details, entity and node add lists, field multiple value form, fieldset, file widget multiple, form element, input (text, boolean, autocomplete, title attribute), links (theme operations, action links, dropbutton, keys as classes), menu local action and tasks, page title, select, status messages, system themes page, table (sortable header, draggable rows), text format wrapper, views view table |
FormHooksTest |
34 | formAlter() branches (entity delete links, views form flex layout, delete form buttons), media and media library add forms, menu link content form layout, node form (sidebar, sticky actions for all three core_admin_theme_use_sticky_action_buttons values, after-build), system modules and theme settings forms, user admin permissions and user form |
ThemeHooksTest |
22 | elementInfoAlter() ordering, container, operations, textFormat (with and without summary, description toggle in and outside content forms), managedFile, messagePlaceholder, themeRegistryAlter(), pageAttachmentsAlter() |
HelperTest |
19 | isContentForm() for shipped routes, module-added routes, altered routes and ignored form IDs, formActions(), isActive(), convertLinkToActionLink(), static caching per method |
SettingsTest |
16 | Defaults from the admin theme, per-user overrides in user.data, userOverrideEnabled(), setAll() and clear(), getSettingsForm() for account and theme settings form |
ThemeSuggestionHooksTest |
12 | Page, form element, region and views suggestions including the page__node de-duplication |
ViewsHooksTest |
12 | viewsPreRender() for the media library and content views, bulk form handling, table markers |
A new test module default_admin_test (tests/modules/default_admin_test/) implements
hook_default_admin_content_form_routes(), hook_default_admin_content_form_routes_alter()
and hook_default_admin_content_form_ignore_form_ids() from default_admin.api.php, so the
alter contract is covered from the module side.
Functional tests (core/themes/default_admin/tests/src/Functional/)
| Class | Cases | Covers |
|---|---|---|
NodeFormTest |
5 | Node edit form layout (two regions, meta sidebar, close trigger), plain page on non-node routes, sticky actions always, content_forms and with navigation installed |
ThemeSettingsFormTest |
5 | The theme settings form alters only default_admin, submit persists and applies, user override section visibility, per-user overrides, disabling overrides clears them |
AdminPagesTest |
9 | Node and block content add lists, admin page blocks (admin-list--panel), appearance page action links, status report, modules page, permissions page, menu link content form layout, sortable and draggable tables |
AdminTest (existing) |
6 | Removed the dead disabledTestUserSettings(); the root user page is loaded through Url::fromRoute('entity.user.edit_form') because $this->rootUser is a UserSession |
Functional Javascript tests (core/themes/default_admin/tests/src/FunctionalJavascript/)
| Class | Tests | What it pins |
|---|---|---|
TableDragTest |
8 | The forked drupal.tabledrag: Drupal.tableDrag.showWeight set on show and removed on hide, toggle wrapper inserted before .table-scroll-wrapper, handle anchor without inner div.handle, svg.tree indentation instead of core's , changed marker as the handle's next sibling, div.tabledrag-cell-content > __item rewrap, body.drag/drag-y, tree-child classes |
TableSelectTest |
3 | data-drupal-sticky-vbo flips, bulk-operations row marking, tr.selected incl. the shift-click range, select-all title flip, clone sync, and a behavioral guard that the theme's misc/tableselect.js replacement is the file actually served |
TableHeaderTest |
4 | Clone revealed, --is-processed, per-column width parity incl. after resize, scrollLeft mirroring both directions |
SidebarTest |
5 | body[data-meta-sidebar], trigger label/aria-expanded/is-active, both sidebarExpanded.* keys with the 1024 px branch measured, ALT+S, drag-resize clamped to 240–560 px writing --admin-theme-sidebar-width + sidebarWidth |
StickyFormActionsTest |
5 | Cloned buttons bound to the real form id, clicking the copy really saves a node, preview relays, Ajax buttons get the mousedown, and the focus shuttle both ways |
AppearanceBootstrapTest |
9 | window.defaultAdminDarkMode, html.dark-mode, stored sidebar width applied at load, style.sidebar-inline-styles injected/skipped, data-admin-focus, style.custom-focus incl. the exact mixed dark value |
SettingsFormTest |
8 | Live preview on both routes: dark mode, high contrast (on <body>, mismatch commented as a defect), accent/focus picker sync both ways, presets, custom colors |
DescriptionToggleTest |
3 | Both halves: preprocess forces description_display: invisible and prints the help button; the behavior labels it and toggles visually-hidden/aria-expanded/aria-hidden; off-state asserted |
| Nightwatch | Corrected the impossible .messages-list__wrapper container to .messages__wrapper; added is-horizontal, data-width, is-open, data-original-order to the tabs spec; added the positive is-autocompleting path |
|
MediaLibraryTest |
3 | Counter is the first child of the dialog button pane, select-all drives every item + announcements + sticky bar, and the form-less grid no longer aborts |
ThemeOverridesTest |
8 | checkbox, dropbutton (markup + fixed positioning), vertical-tabs, details, password strength, message dismiss, media embed error markup |
Bugs fixed in the MR
The tests fail against the original code for these three, so the fixes are in the MR.
PreprocessHooks::preprocessLinks()iterated$variables['links']by value. Theaction-linkclasses and key-based classes it computes never reached the render array. Fixed withforeach (... as &$links_item)andunset($links_item).ThemeHooks::elementInfoAlter()registered[ThemeHooks::class, 'textFormat']twice ontext_format(once through the loop, once through anarray_key_exists()block). The callback is not idempotent, so the wrapper classes were added twice. The second registration is removed.templates/dataset/table.html.twigdecided betweenth__itemandth__<label>with'<a' in cell.content|render|render. Since #2334319 (2c8c0a2efb2)TwigExtension::renderVar()returnsMarkupInterfaceobjects unchanged, and Twig'sinoperator only stringifies\Twig\Markup, so the comparison was alwaysFALSE. Sortable headers receivedth__a-href-...classes built from the whole anchor markup. The template now compares againstcell.content|render|trim, which yields a plain string (same idiom asolivero/templates/content/page-title.html.twig).- description_toggle library had no dependencies - CI artifact proved description_toggle.js was served before core/misc/drupal.js, so Drupal was undefined and the feature was dead in the shipped theme. Audited every library: 13 missing dependency lines added (core/drupal for accent, settings, sidebar, more_actions, navigation, tableheader, escape_admin; core/drupal.debounce for sidebar, dropbutton, tableheader; core/drupal.displace for navigation). core/drupalSettings does not depend on core/drupal, so those entries were genuinely unguarded.
- media_library.view.js dereferenced three nulls - a media library page display without a bulk form throws a TypeError that also kills the per-item click binding. Guarded in the file's own optional-chaining style.
Additional issues fixed in this MR
The issues from this comment have also been fixed.
Disclosure: I used the help of an LLM to spin up the tests.
Edited by Jürgen Haas