Problem/Motivation
As a spin-off from #3037228: Add more test coverage to Help Topics, we would like to ensure that all topics written for the new Help Topics Core module have proper syntax, for all non-test modules in Core.
Proposed resolution
Add checks for the following syntax issues:
- Meta tag for the title (label) must be present (help_topic:label)
- Topic must be either top-level or related to a top-level topic
- HTML syntax is valid (without the Twig stuff and meta tags)
- All text in the topic is wrapped in Twig translation tags.
- No H1 tag
- If there is an H3, there should be an H2, and so on
- The topics can be viewed at their URL
Things we are not explicitly testing in this test:
- The discovery process already reads label, related, and top-level from the meta tags, so this test can use the result instead of verifying the meta tags itself.
- The discovery process throws an exception if any other meta tags are encountered
- We are only testing Core. It would be desirable to also test Contrib but I'm not sure how we could accomplish this... but as a note, if a particular contrib module is in the file system when you run these tests, it will be discovered and tested.
Remaining tasks
Add the checks.
User interface changes
None
API changes
None
Data model changes
None
Release notes snippet
Added new checks to ensure Help Topic Twig files have proper syntax.
ISSUE CREDIT
This was spun off from #3037228: Add more test coverage to Help Topics and a patch there was the starting point:
https://www.drupal.org/files/issues/2019-07-08/core-add-more-test-covera...
Please credit scott_euser on this issue, who created that patch, and jhodgdon, who reviewed it.
Comment | File | Size | Author |
---|---|---|---|
#58 | 3066512-58.patch | 16.42 KB | alexpott |
#58 | 51-58-interdiff.txt | 8.53 KB | alexpott |
#52 | 3066512-51.patch | 17.8 KB | Amber Himes Matz |
#52 | interdiff-50-51.txt | 1015 bytes | Amber Himes Matz |
#50 | 3066512-50.patch | 17.33 KB | jhodgdon |
Comments
Comment #2
jhodgdonWe have a few more syntax checks to add to this issue.
Comment #3
jhodgdonComment #4
jhodgdonAdding note about not checking that only the currently-defined meta tags are there.
Comment #5
jhodgdonIt appears that Coder does not work on Twig files, only PHP.
So, I'm moving this back to Drupal Core to figure out how to check syntax of Twig files, and updating issue summary.
Comment #6
jhodgdonSince we are doing this in Core, let's expand the scope slightly to include testing whether the topics can be displayed.
Comment #7
jhodgdonI don't think it's going to be possible to have a test that works for contrib, as far as I can tell. Updating issue summary.
Comment #8
jhodgdonThere's a patch on #3037228: Add more test coverage to Help Topics that should probably be here instead.
https://www.drupal.org/files/issues/2019-07-08/core-add-more-test-covera...
Please credit scott_euser on this issue.
[adding this to the summary]
Comment #9
jhodgdonI am going to start working on this today and see what I can do...
Comment #10
jhodgdonOK, here we go! I think I managed to test everything in the issue summary that could be done without actually rendering the topic with Twig, which I am not sure will work well due to the variable stuff (routes may not be defined). As a note, I had to filter out test modules and themes in order for the tests to pass, which tells me that they are good tests (we intentionally have some bad topics in the test files under help_topics/tests/modules and help_topics/tests/themes).
Oh wait... OK I made one interdiff and then realized I could probably test one more thing. So, the first interdiff is from Scott's patch from the other issue, and the 2nd is the additional changes I made.
Anyway, let's make sure the test bot agrees, but this test passes locally with 164 assertions.
Comment #11
jhodgdonOh, one other note: I did have to edit one topic file, because it failed the test -- it listed a topic as "related" that was the wrong ID.
Comment #12
larowlanThis is some nice work!
do we need to consider profiles here too?
could use array_filter here?
could pass $top_level_ids as a variable and avoid $this->topLevelIds, would be more portable if ever needed to move verifyTopic to a trait
nice
we should use the third argument here because the values are expected to be strings
no need for an else after a $this->fail
we could flip this and $this->fail anytime the item was missing, instead of keeping track over the loop, i.e call $this->fail in the loop as soon as things go bad
could use assertNotEmpty?
I'm not sure what the point of this is? Are you asserting there's nothing that is outside a trans tag?
and could use assertEmpty here
nice
nice!
Comment #13
jhodgdonAddressed, I think, all the review comments in #12 -- either by changing code or updating comments so it's clearer what is happening and why (I hope!). A few notes:
Comment #14
scott_euser CreditAttribution: scott_euser as a volunteer and at Soapbox Communications Ltd commentedThanks for taking this forward - looks good!
More of a side note, but I saw this in the issue description:
We do this in the HelpTopicDiscovery class:
I am wondering if that means that no additional meta tags can be added and we do actually still need a test for that? If its the case that HelpTopicDiscovery itself is potentially extended, we could conditionally wrap the test in the condition that its the HelpTopicDiscovery coming from the help_topics core module, eg:
Other than that which is perhaps more of a question, RTBC from me!
Comment #15
jhodgdonGood question... I hadn't realized that we were throwing an exception if an unrecognized meta was encountered. Let's just leave it as it is, and I'll update the issue summary with a proper list of what we're testing and what we're not testing.
I did add a note that there is (somewhere) in Core a module install/uninstall test that goes through every module in core and does some basic tests. We could potentially add to that so that in addition to the hook_help test it is already doing, we load all the help topics and render them with Twig, to verify they will render. We can't really do that here due to Twig variables for URLs probably not working.
I think it makes sense to see if that can be done in this issue, so let's leave it at Needs Review for the moment and I'll take a shot at that.
Comment #16
jhodgdonHm. I took a look at InstallUninstallTest
I expect that we don't want to add an Experimental module's tests to that code. So... we either need to
a) Postpone adding a test to render all the Twig topics until this module is Stable.
b) Write a separate test that would take a long time to run, and do something similar to InstallUninstallTest, (install modules one by one) but verify the help topics instead of the hook_help (and omit all the testing that modules can be installed/uninstalled). Plan to fold it into InstallUninstallTest eventually.
c) Write a test that would install all the non-hidden and non-test modules at once, and verify all the help topics can be rendered. This would not be as rigorous as testing with the modules individually installed, because it might mask problems in routes not being defined, but it would be better than nothing.
I think I'll do (c), but also create a follow-up issue to add to #3037230: Finalize the merge of Help Topics into Help that would fold the test into InstallUninstallTest so it would be more rigorous. If the test fails at that time, we can adjust the topics then.
Comment #17
jhodgdonI created the follow-up issue, and here is a patch that checks rendering. Updating summary. I also made a trait to do some things that were needed for both the kernel test and the rendering test.
Comment #18
jhodgdonAddressing 2 coding standards issues from last patch. I edited patch file directly (took out 2 spaces and added 1 space) and did not make an interdiff, hope that is OK, it's exactly the same code.
Comment #19
andypostIt looks great, just one more question about code duplication with discovery of extensions
I see this duplicate a lot of code for each test to collect directories, but tests are part of core
So instead of
strpos()
the\Drupal\Core\Extension\ExtensionDiscovery::scan()
could filter out testing modules.It makes it more inline with
HelpTopicDiscovery::findAll()
- which could be extended with$include_tests = FALSE
argument (probably follow-up)Comment #20
jhodgdonI ran into a lot of problems when I was running this test interactively and trying to get it to run, because if it discovering themes, modules, and profiles that were really just for testing -- which is why I ended up with strpos. If you know of a way to make a list of modules, or themes, or profiles that will get everything (not the ones currently installed) and exclude testing ones, yes, let's do it. But I couldn't figure it out from the documentation of those service classes. ?? strpos seemed the simplest option that actually works.
Also, the difference between the Kernel test and the Functional test is that in the Functional test, we actually need to install the modules/themes so we can test rendering. The reason for that is that the rendering uses routes that would not be defined without the modules enabled. But the Kernel test is very quick and doesn't actually render anything. They could be combined, but I was under the impression that we wanted as much testing as possible to live in Kernel tests and not Functional, so I left them as two separate tests (with a trait to reduce code duplication as much as I thought was possible).
So... Not sure what you want done with the tests here?
Comment #21
jhodgdonPS: I would really like to get this resolved/committed as soon as we can, so that people writing new help topics as part of #3041924: [META] Convert hook_help() module overview text to topics will see a test fail if their help topics do not pass these tests. Thanks!
Comment #22
jhodgdonTo reduce duplicated code, I folded the Kernel and Functional test into one test. I decided it didn't make sense to have two separate tests running the same discovery. I didn't make an interdiff for this merge -- it would have been almost the complete patch, so it seemed pointless. But it's the same code, just merged together, including all of the asserts from both of the tests, and the methods from the helper trait.
After I did that code merge, I took a look at the question of whether I could get rid of the strpos stuff (see comment #19). Here is the code I ended up with in listDirectories():
As you can see, first I ran into #3076098: ExtensionDiscovery documentation is wrong about scanning profile directories, which I had to put in a strange work-around for.
And then, even with this work-around, it still found all the testing profiles in its scan, in spite of the fact that I told it to NOT find testing items. Here's the list of profiles it found:
I didn't create an issue for that yet. But I think the strpos is the best solution until these bugs in the discovery process are fixed.
Also as a note, if we want to use the above code, there is something missing from the paths it is returning, because the HelpTopicDiscovery found no topics. So that would also need to be fixed.
Anyway, here is the patch with the single merged test.
Comment #23
jhodgdonCreated issue for the other problem with ExtensionDiscovery
Comment #24
jhodgdonAs one more note: If you look at InstallUninstallTest, you will see that after scanning all modules, it then filters them:
So it is filtering modules based on what is in the .info.yml file -- excluding modules marked "hidden" or in the "testing" package.
An earlier version of this patch (which I don't think I ever uploaded) did something similar, but then when I got to themes and profiles this scheme didn't work... which again is why I ended up with the strpos filtering, which does work even though it is kind of crude.
So... once again... I think for this test we should just leave the strpos in, and not try to solve the related issues in ExtensionDiscovery when we really need to get a test in place for help topic syntax before we get too far in writing new topics (which is happening now).
Comment #25
andypostOnly one nitpick - property visibility, metadata is only a question of strictness
This property is protected in parent class
Not sure how strictly it should test metadata but
- label and related covered (both name and content attributes)
- for "top_level" - should it make sure that this meta has no other attributes?
Comment #26
andypostthe $info is not used, so I'd add
$names = array_keys($lister->getAllAvailableInfo());
Comment #27
jhodgdonRegarding the meta-data, the code in HelpTopicDiscovery does this:
So it looks like we have that covered. At least, it's verifying that there isn't anything in the value. It's not valid HTML syntax to have anything but name/value attributes on a meta-tag.... I think that's good enough?
Taking your other two suggestions though. [That $info was being used while I was developing the patch (I was trying to use it to filter out hidden modules/profiles) but I stopped using it and never took it out of the patch.] Let's see how this goes...
Comment #28
jhodgdonI think we can add some more tests to verify discovery and topic syntax fails in the ways we expect. Setting this to Needs Work until I have that done.
Comment #29
jhodgdonOK, here's a new patch, which adds some more discovery tests. This verifies that all the exceptions in HelpTopicDiscovery will be triggered with suitably bad Twig files. I switched from using a virtual file system to having actual topic files in a "bad_help_topics" subdirectory of the test module. Thoughts?
Comment #31
jhodgdonAh. That last patch changed an Exception message (when I went to test it, I realized it was kind of written unclearly, so I updated it), and another test depended on that. So, fixing that. Also the coding standards error (unused use statement for the virtual file system that last patch doesn't use any more).
Also I thought up how to test the other syntax things, to make sure the test will catch the errors it should catch.
I don't have time to finish these updates today, but I'm working on them...
Comment #32
jhodgdonOK, here it is! See previous comment for what this patch does.
Comment #33
jhodgdonThe test bot likes it. I think it's ready for final review/commit. Any thoughts?
Comment #34
jhodgdonThis is the last issue for Beta for Help Topics that is not at RTBC. Any thoughts?
Comment #35
andypostStill applies clean, I see nothing to add here
Comment #36
larowlanthese look like data providers, so should we use a dataProvider? or is this done on purpose because of the setup cost of a browser test?
These are an implementation feature of PHPUnit - and we're inadvertently coupling ourselves to a specific version of phpunit (those classes don't exist in phpunit version > 4 and are only provided via a BC shim in our bootstrap.php).
I think instead we should catch the bad parsing in the discovery layer and throw our own specific exceptions. i.e. I would prefer we refactored the test to catch our actual exceptions instead of relying on their implementation details.
E.g the code throws DiscoveryException, so shouldn't we be catching that instead?
Comment #37
andypostThe first one is definitely because of browser test, if we make it with dataProvider it will setup core for each case
The second a bit tricky
- invalid html catchable with libxml flags https://www.php.net/manual/en/libxml.constants.php so no exception could be used
- second is result of exception in child site, will debug how to catch it in different way
Comment #38
andypostSomehow it makes sense to limit the test to scan only core...
I got few contrib modules in "modules" dir and they cause test failures
Comment #39
jhodgdonRE #38 - limiting the test to scan for only Core is probably a good idea, although if we don't do that, then a contrib maintainer could run the test on their contrib module and also verify their module's help topics are good?
RE #37... I think the idea in #36 of catching the parsing in the discovery layer and throwing our own specific exception makes more sense than what we are currently doing. I will not have time to make a patch to do that in the next 2 days, but I would have time to review one if @andypost makes a patch. Otherwise, I might have time to make a patch on Friday.
Comment #40
jhodgdonI came up with some time today, so I will make the next patch now.
Comment #41
jhodgdonHere's a new patch that:
(a) Only looks at topics in Core
(b) Removes the use of
As a note, this was in there for the HTML parsing step in the test (not in Discovery), so I modified that code to use the XML library's error handling instead of PHP warnings, and I didn't have to modify the Discovery class.
(c) Changes
so that it looks like core/modules/system/tests/src/Functional/Menu/BreadcrumbTest.php and core/tests/Drupal/FunctionalTests/BrowserTestBaseTest.php ... I hope that is sufficient? If not... What we want to do in this test is to assert that a given topic fails the verifyTopic() method in the expected way (generates the expected assertion fail message). Is there a better way to do that? If so, we should fix this test and the other two in Core in the same way.
Comment #42
jhodgdonFix coding standards messages.
Comment #43
Ghost of Drupal Past(that last could be preg_grep just in case someone rerolls the patch but it's fine as is)
Comment #44
jhodgdonWant to RTBC it then? :)
Comment #45
andypostRe #43 - I think
strpos()
is faster here instead of preg..Comment #46
alexpottThis feels like a duplicate of existing tests - see \Drupal\Tests\help_topics\Unit\HelpTopicDiscoveryTest - if there is something missing it should be added there. I can't find anything in this test that is not covered in that test.
Comment #47
jhodgdonDoh! You are totally right. Here's a patch that removes that part of the test.
Comment #48
andypostI think it makes sense to follow up to decouple unit vs functional tests better, but current patch is about syntax tests
Comment #49
jhodgdonThis is going to need a small update now that #3069109: Replace help_topic meta tags with front matter is in. Also a reroll for the test help topics (new format).
Comment #50
jhodgdonHere is a new patch. What has changed:
a) Help topics added in this patch have front-matter metadata instead of meta tags. So, things like:
become
That change is made in all the topics.
b) The syntax test had to be modified to remove front matter instead of meta tags in its syntax checking:
became
Along with a change to the error message for meta tags being gone:
(used to say "outside of meta tags").
Comment #51
jhodgdonComment #52
Amber Himes MatzI've reviewed @jhodgdon's patch in #50 and it looks good to me...except for a couple of errors in a comment. I've attached an interdiff and a new patch fixing a typo and updating a TODO URL to the actual issue. (The one linked has been closed as a duplicate.)
Comment #53
Amber Himes MatzIn the patch's core/modules/help_topics/tests/src/Functional/HelpTopicsSyntaxTest.php:
Looks like we are looking for Twig
trans
tags to strip out, along with whitespace and HTML. But we also can have Twigset
tags to set a URL up, for example:So, do we need to add to that
preg_replace
to account for Twigset
tags?Comment #54
jhodgdonThanks for the new patch! Interdiff looks good to me.
Regarding #53, we are already removing set statements a few lines up from there:
So I think we're good. We have set statements in several of the existing core topics, which are all (with this patch) passing the tests.
Comment #55
Amber Himes MatzGreat! I'm +1 for an RTBC. Do we need another review?
Comment #56
Ghost of Drupal PastLooking at deadlines and the road map parent issue, I say we do this contingent upon #3086075: Use Twig to strip Twig syntax from help topics files in the syntax checker happens before we deem it stable.
Comment #57
jhodgdonThat sounds like a good idea. I'll add that to the Roadmap issue for Stable.
Comment #58
alexpottHere's a few tidy ups:
assertSomething
methodsComment #59
jhodgdonWow, that's a lot of assertSomething methods I didn't know about. ?!?
+1 for leaving this at RTBC. Changes look fine.
Comment #60
alexpottCommitted 41a9b82 and pushed to 8.8.x. Thanks!
@jhodgdon PHPUnit has a lot of
assertSomething
that are really nice and have excellent messages.Totally agree with the follow-up #3086075: Use Twig to strip Twig syntax from help topics files in the syntax checker - was going to ask for it here - +1 on have that as a stable blocker.