Problem/Motivation
As part of improving the theme system and making everything renderable in Drupal 8, we are removing all calls to theme() from core, and instead calling drupal_render() on structured data.
This particular issue is where we will post the patch to remove all calls to theme() from the simpletest module in core. This is one of the sub-issues from our meta: #2006152: [meta] Don't call theme() directly anywhere outside drupal_render()
In most core modules, we simply remove all calls to theme(), but in simpletest module we need to be more careful, because we do have tests that need to call theme() in order to test that the theme_hook_suggestions are working correctly.
Note that WebTestBase::assertThemeOutput()
must work for both theme hook types, but is currently broken for theme hooks that work with a render element instead of variables. The patch in #47 proves and fixes this.
Proposed resolution
Remove all calls to theme() from simpletest module.
Remaining tasks
Remove all calls to theme() from simpletest module.
User interface changes
None.
API changes
None.
Related Issues
#2006152: [meta] Don't call theme() directly anywhere outside drupal_render()
Comments
Comment #1
esunger CreditAttribution: esunger commentedWDG (Ukraine,Kharkov) want to implement this on CodeSprintUA.
Comment #2
esunger CreditAttribution: esunger commentedComment #3
esunger CreditAttribution: esunger commentedUpdated assertThemeOutput function in /core/modules/simpletest/lib/Drupal/simpletest/WebTestBase.php.
Comment #4
esunger CreditAttribution: esunger commentedComment #5
podarokhttps://drupal.org/coding-standards#indenting
whitespace errors
needs whitespaces around of
=>
Comment #6
esunger CreditAttribution: esunger commentedThanks, whitespace errors were solved.
Comment #7
podarok#6 not solved
try http://dgo.to/dreditor and look at Your patch
whitespace indenting not tabs
whitespace endings
still needs work
Comment #8
JeroenTSolved whitespace issues in patch #6.
Comment #10
JeroenTSolved whitespace issues in patch #6.
Comment #11
thedavidmeister CreditAttribution: thedavidmeister commentedThis has nothing to do with this issue. Remove it from the patch please.
This variable should be called $build, not $theme. Please see the issue summary of the parent issue for more details.
This variable should be $item_list not $items_list.
I do feel like the concatenation of the links to the rendered images could just be included as #suffix attributes on the image arrays themselves.
Comment #12
JeroenTMade changes as suggested by thedavidmeister.
I also changed the alt and title because i think this is wrong.
Comment #13
JeroenTMarking as needs review.
Comment #14
JeroenTaccidentally deleted tag.
Comment #15
thedavidmeister CreditAttribution: thedavidmeister commentedThe alt and title were correct originally. Please don't change functionality in a conversion patch like this, open a separate issue if you want to change things.
When something is currently "collapsed" you want to show the verb that will happen when you click it, which is "expand" not "collapse". And vice versa.
Regardless, need a separate issue for proposed changes.
Comment #16
hussainwebRemoving changes to 'alt' and 'title' and fixed minor whitespace issues. Also note that there is a possible error with the class name for the link in suffix:
I have left it like this for now.
Comment #18
thedavidmeister CreditAttribution: thedavidmeister commented#16 - the class name does look like an error, why not open a followup issue for it?
Comment #19
hussainweb#16: simpletest_replace_theme_with_drupal_render-2009670-16.patch queued for re-testing.
Comment #21
jenlampton#16: simpletest_replace_theme_with_drupal_render-2009670-16.patch queued for re-testing.
Comment #22
hussainwebLooks like all the tests have passed on the patch in #16.
Comment #23
heddn#16 looks good to go. #2021551: Possibly confusing class name in simpletest.pages.inc is opened to fix the CSS class name.
Comment #24
YesCT CreditAttribution: YesCT commentedThis issue was RTBC and passing tests on July 1, the beginning of API freeze.
Comment #25
alexpottCommitted 6038891 and pushed to 8.x. Thanks!
Comment #26
Eric_A CreditAttribution: Eric_A commentedassertThemeOutput()
was designed for modules to prevent regressions in their theme hook implementations. It takes just a theme callback en variables. This hunk should be reverted.Comment #27
Eric_A CreditAttribution: Eric_A commentedComment #28
Eric_A CreditAttribution: Eric_A commentedThe breaking of test coverage cannot be a normal task...
Comment #29
jenlampton@Eric_A The change above should not break tests. Are you sure it does?
Calling drupal_render() on a render array with
"#theme' => 'callback'
should produce exactly the same output as calling theme('callback'). Since this test only needs the $output from that call, there should be no regression here.Additionally, since there will be no calls to
theme()
anywhere else in core, this test *should* test the output in the same way it will be generated, which is via drupal_render().Changing issue status back.
If there is actually a problem with this test, can you create a follow-up issue that references this one?
Comment #30
Eric_A CreditAttribution: Eric_A commentedAgreed that it *should* produce the exact same output, but this is not always the case (See #2041283: theme_status_report() is severely broken). Anyway, this is a low level method that was introduced to test theme function output directly, not the drupal_render() route. See #1706878: Add WebTestBase::assertThemeOutput() to allow modules to test theme function output. If we had an assertThemeOutput() for theme_status_report() it would have failed with the patch that was committed here. So yes, the drupal_render() implementation is useful, it may make loads of sense to create a method for testing the output returned from the drupal_render() route, but that one should get a name different from assertThemeOutput() and we should not just throw away the low level testing in a completely different issue.
Fixing this regression here as a quick follow-up does look like the right thing to do.
Comment #31
Fabianx CreditAttribution: Fabianx commentedHm, if drupal_render() != theme() that is a bug in itself. So I don't see the need for it that core calls a soon-to-be-deprecated function.
Comment #32
Eric_A CreditAttribution: Eric_A commentedI don't think the theme() system is soon-to-be-deprecated at all. Rather, soon-to-be-considered-internal.
Yes, the idea is to use the higher level render API instead of calling theme() directly. But the theme() system will still be around, theme hook implementations will still need to be provided by modules, and there should still be a way to *test* these components on their own, by directly calling these functions. So yes, I'm saying drupal_render() != theme() and I don't consider that a bug at all.
Comment #33
Fabianx CreditAttribution: Fabianx commentedWell, from the function definition of drupal_render => drupal_render with appropriate input is always equal to theme and anything else is a bug.
And if we deprecate theme() as public function, which we do, then Drupal internally would call a deprecated public function, which feels strange, but should be okay.
But I don't have strong feelings about this here and I am fine with either way and let the core committers to decide.
Comment #34
catchWouldn't that be a good thing?
Comment #35
Eric_A CreditAttribution: Eric_A commentedIt is true that a drupal_render() version of this test helper can uncover bugs in theme hook implementations that take a render element. But theoretically it could go another way. A bug in drupal_render() could make a test pass or fail when it shouldn't. We're adding more and more unit testing. Surely we can't do this at the same time? At least not hidden in this issue.
Expanding the original test helper by adding a #theme property when the hook needs a render element gets us the same coverage, but without the dependency on drupal_render(). I'd be happy to do that.
Comment #36
Eric_A CreditAttribution: Eric_A commentedWhen you look at the two tests that currently call
assertThemeOutput()
there's more evidence that we've broken the contract:\Drupal\system\Tests\Theme\FunctionsTest::testItemList()
- "Tests theme_item_list()."\Drupal\system\Tests\Theme\FunctionsTest::testLinks()
- "Tests theme_links()."I just learned that we have
\Drupal\system\Tests\Common\RenderTest
which extends\Drupal\simpletest\WebTestBase
. We could overrideWebTestBase::assertThemeOutput()
inRenderTest
(or whichever test class makes the most sense). So we'd be restoring the original contracts and have a drupal_render() version for tests that want to "Assert basic render element output" rather than "Assert themed output".Comment #37
eromero1 CreditAttribution: eromero1 commentedThe patch was installed and the testing module ran swimmingly. Everything is looking dandy. GO TEAM DRUPAL!!!!
Comment #38
catchStill needs review.
Comment #39
Eric_A CreditAttribution: Eric_A commentedCould this perhaps be assigned to @tim.plunkett or @effulgentsia? @tim.plunkett did #1706878: Add WebTestBase::assertThemeOutput() to allow modules to test theme function output and @effulgentsia maintains both Theme system and Render system.
Comment #40
Fabianx CreditAttribution: Fabianx commentedWe will be deprecating theme() as it is - that has been decided now on twig call. The only way to get output from theme() will be drupal_render() going forward (from D9 then). This solves a lot of major tasks for the theme system cleanup and drillability and how to make #type work.
There will be a theme_info() call and theme() will just be a wrapper around it probably that calls the #render_function gotten from theme_info() with the #render_variables. (Issue link is coming as soon as I have written this up).
I am fine to change this back and forth, but in the end this will be changed anyway.
Unit Testing is great - yes. The question is: Where is the "border" of calling internal APIs?
Maybe another option is to change the function name of themeTest to renderTest to make clear it is testing drupal_render() and not theme() - soon to be deprecated?
Thanks!
( Removed tags on purpose as they don't apply to the current patch and this is not Novice. )
Comment #41
Eric_A CreditAttribution: Eric_A commentedWhy would deprecation of
theme()
in itself mean that we no longer care about (unit) testing module provided parts in a low-level output generating subsystem? If we cannot usetheme()
anymore, then we'll use what comes closest. Which can never be any higher level Render API. If we want to remove this level of testing, that's a different issue. (It's not a conversion issue, that's for sure.)When testing the output of a template and its (pre)processors we really don't care much what clients will be using all of this. The notion of Drupal render elements and #type properties are irrelevant here.
Right now
assertThemeOutput()
has become incomprehensible for anyone who knows what it was about, reads the current doxygen and then takes a look at the current implementation.Comment #42
webchickHm. I don't fully grok what the problem is here, and it seems like there is disagreement within the Twig team about whether or not it actually is a problem.
If something needs to get rolled back, let's get agreement on this and an updated issue summary that explains what's going on to core committers.
Comment #43
jenlamptonChanging status back to CNR
Comment #43.0
jenlamptonactual summary
Comment #44
jenlamptondoing my homework.
Comment #45
jenlamptonOkie dokie, I just re-read everything and updated the issue summary. And here's what I think we should do:
1) Use the patch in #27 since that fixes broken tests, which we introduced in the initial commit.
2) We should add a test that will fail appropriately without the patch in #27, as per #34.
3) We will be deprecating theme() - or making it internal - or whatever - later on. Let's postpone the rest of the debate (including calling only drupal_render() in tests, renaming themeTest to renderTest, etc) until then, and at least get things back in a working order right now.
Comment #46
Eric_A CreditAttribution: Eric_A commentedAnother regression:
assertThemeOutput()
no longer works when passing a renderable array as the only argument. The current implementation just expects that it is passed an associative array of variables, which I believe is an unneeded assumption. TheassertThemeOutput()
method "Asserts themed output", so a full functional mapping to theme() is what really helps client code.@jenlampton, are you working on this? Otherwise, I might give it a shot.
Comment #47
Eric_A CreditAttribution: Eric_A commentedI went looking for existing assertions involving renderable array theme hooks and found a few in
\Drupal\system\Tests\System\ThemeTest
. I converted all assertions toassertThemeOutput()
and expect the ones involving renderable array theme hooks to fail without the fix from #27.Comment #48
Eric_A CreditAttribution: Eric_A commentedSo the testbot revealed yet another issue:
theme()
and the fixed version ofassertThemeOutput()
return the same value if the passed $callback is not implemented. (Currently this is the boolean FALSE.) The current version ofassertThemeOutput()
returns whatdrupal_render()
returns. (Currently the empty string.)Comment #49
Eric_A CreditAttribution: Eric_A commentedSo the testbot revealed yet another issue:
theme()
and the fixed version ofassertThemeOutput()
return the same value if the passed $callback is not implemented. (Currently this is the boolean FALSE.) The current version ofassertThemeOutput()
returns whatdrupal_render()
returns. (Currently the empty string.)Comment #50
jenlamptonYes, I was working on these tests. That's why I assigned it to myself ;)
I decided to use assertIdentical() instead of assertThemeOutput() to confirm that the output from theme() and drupl_render() are identical. Unfortunately, the output was identical. Even without this patch.
Since your tests catch the bug you were referring to (and mine don't) I'll leave this to you.
Comment #50.0
jenlamptonupdate
Comment #50.1
Eric_A CreditAttribution: Eric_A commentedWebTestBase::assertThemeOutput() currently broken for theme hooks that work with a render element instead of variables.
Comment #51
Eric_A CreditAttribution: Eric_A commentedAdded the most pressing part of the current state to the issue summary.
Note that
WebTestBase::assertThemeOutput()
must work for both theme hook types, but is currently broken for theme hooks that work with a render element instead of variables. The patch in #47 proves and fixes this.Comment #52
catchTest looks fine. Let's go back to how it was for now and revisit later.
Comment #53
alexpottCommitted cc1f3fd and pushed to 8.x. Thanks!
Comment #54.0
(not verified) CreditAttribution: commentedIndicated one of the differences with the earlier patch.