Test::...Content(3pm)
π Test::HTML::Content β or as the manpage header calls it, Test::...Content(3pm) π
okay bestie, sit down, hydrate, because we're about to test some HTML and it's gonna be so satisfying. this is a Perl extension for testing HTML output. no cap. π¦
β¨ NAME β¨
Test::HTML::Content β Perl extension for testing HTML output. it's giving "QA but make it cute". π
πΈ SYNOPSIS πΈ
here's the whole vibe, verbatim, because you will be copying this:
use Test::HTML::Content( tests => 13 );
$HTML = "<html><title>A test page</title><body><p>Home page</p>
<img src='http://www.perl.com/camel.png' alt='camel'>
<a href='http://www.perl.com'>Perl</a>
<img src='http://www.perl.com/camel.png' alt='more camel'>
<!--Hidden message--></body></html>";
link_ok($HTML,"http://www.perl.com","We link to Perl");
no_link($HTML,"http://www.pearl.com","We have no embarassing typos");
link_ok($HTML,qr"http://[a-z]+\.perl.com","We have a link to perl.com");
title_count($HTML,1,"We have one title tag");
title_ok($HTML,qr/test/);
tag_ok($HTML,"img", {src => "http://www.perl.com/camel.png"},
"We have an image of a camel on the page");
tag_count($HTML,"img", {src => "http://www.perl.com/camel.png"}, 2,
"In fact, we have exactly two camel images on the page");
no_tag($HTML,"blink",{}, "No annoying blink tags ..." );
# We can check the textual contents
text_ok($HTML,"Perl");
# We can also check the contents of comments
comment_ok($HTML,"Hidden message");
# Advanced stuff
# Using a regular expression to match against
# tag attributes - here checking there are no ugly styles
no_tag($HTML,"p",{ style => qr'ugly$' }, "No ugly styles" );
# REs also can be used for substrings in comments
comment_ok($HTML,qr"[hH]idden\s+mess");
# and if you have XML::LibXML or XML::XPath, you can
# even do XPath queries yourself:
xpath_ok($HTML,'/html/body/p','HTML is somewhat wellformed');
no_xpath($HTML,'/html/head/p','HTML is somewhat wellformed');
likeβ¦ look at her. she's gorgeous. ππ
π DESCRIPTION π
so basically, this is a module that tests the HTML output of your programs inside simple test scripts. it takes a scalar (presumably stuffed with HTML) and checks for the presence β or the absence, or a specific number β of tags that have (or don't have) specific attributes. π
the rules, bestie, listen up:
- attributes you don't specify are just ignored. not our business, not our problem.
- attribute values can be given as scalars β meaning a match succeeds if the strings are identical
- or as regular expressions β meaning a match succeeds if the actual attribute value is matched by the given RE
- or as
undefβ meaning the attribute must not be present. periodt.
now. if you want to test the deeper structure of the HTML (think META tags inside the BODY, iykyk) or the (textual) content of tags, you're gonna have to pull out the big girls: xpath_ok, xpath_count and no_xpath, which take an XPath expression. π₯
and real talk? if you catch yourself crafting very complex XPath expressions just to verify the structure of your output, that's your sign from the universe to rethink your whole testing process. maybe use a template-based solution, or honestly just compare against prefabricated files as a whole. the vibes are telling you something. π
the HTML parser used here is HTML::TokeParser, and the XPath module used is XML::XPath or XML::LibXML. heads up:
- XML::XPath needs valid xHTML. it's picky like that.
- XML::LibXML will try its best to force your code into xHTML (iconic effort tbh), but it's genuinely best to just supply valid xHTML (snippets) to the test functions. π«Ά
and here's the good part β if no XPath parsers/interpreters are available, the tests will automatically skip, so your users won't need to install XML::XPath or XML::LibXML. no forced dependencies, we love a considerate queen. π
in that case the module falls back onto a crude implementation of the core functions for tags, links, comments and text β and the diagnostic output of the tests varies a bit. just so you know what you're getting. π
the test functionality is derived from Test::Builder, and the export behaviour is the same. when you use Test::HTML::Content, a set of HTML testing functions gets exported into the namespace of the caller. πͺ
π EXPORT π
exports the whole bunch of test functions:
link_ok() no_link() link_count()
tag_ok() no_tag() tag_count()
text_ok no_text() text_count()
comment_ok() no_comment() comment_count()
xpath_ok() no_xpath() xpath_count()
has_declaration() no_declaration()
look at that lineup. it's giving squad goals. β
π§ CONSIDERATIONS π§
ngl, the module reparses the HTML string every single time a test function is called. so if you're running many tests over the same, large HTML stream, it's gonna be relatively slow. π
a possible speedup would be a simple-minded caching mechanism that keeps the most recent HTML stream in a cache. just saying. putting it out there. π
π CAVEATS π
the test output differs between XPath and HTML parsing, because XML::XPath delivers the complete node including the content, whereas the HTML parser here only delivers the start tag. so don't make your tests depend on the _exact_ output of these tests. it was a whole pain to do that in the test scripts for this module, and if you really want to, go take a look at the included test scripts. you've been warned bestie. π
also β the title functions title_ok and no_title rely on the XPath functionality, and will thus skip if XPath functionality is unavailable. no XPath, no title testing, that's the deal. π€·
π BUGS π
currently, if there's text split up by comments, the text will be seen as two separate entities, so this does not work:
is_text( "Hello<!-- brave new--> World", "Hello World" );
whether this is a real bug or notβ¦ honestly don't know at the moment π
β most likely, text_ok() and siblings will be modified to ignore embedded comments. so, watch this space. π
β TODO β
the things on the todo list for this module. patches are welcome! π«Ά
- Refactor the code to fold some of the internal routines
- Implement a cache for the last parsed tree / token sequence
- Possibly diag() the row/line number for failing tests
- Allow RE instead of plain strings in the functions (for tags themselves). This one is most likely useless.
that last one said "most likely useless" and honestly? respect for the honesty. π
π LICENSE π
this code may be distributed under the same terms as Perl itself. slay. β¨
π AUTHOR π
Max Maischein <corion@cpan.org> β the icon, the legend, the moment. π
π¦ SEE ALSO π¦
perl(1), Test::Builder, Test::Simple, Test::HTML::Lint.
and that's the whole page bestie!! π₯³ this little gem lives in perl v5.40.0 and it was last touched on 2024-08-17. go forth and test your HTML, you absolute main character. πβ¨πΈπ¦ππ
π¦ where this page comes from
- ubuntu resolute: libtest-html-content-perl 0.13-1 Β· Artistic-1.0-Perl OR GPL-1.0-or-later
- ubuntu stonking: libtest-html-content-perl 0.13-1 Β· Artistic-1.0-Perl OR GPL-1.0-or-later
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms