.\" Automatically generated by Pod::Man 4.14 (Pod::Simple 3.43) .\" .\" Standard preamble: .\" ======================================================================== .de Sp \" Vertical space (when we can't use .PP) .if t .sp .5v .if n .sp .. .de Vb \" Begin verbatim text .ft CW .nf .ne \\$1 .. .de Ve \" End verbatim text .ft R .fi .. .\" Set up some character translations and predefined strings. \*(-- will .\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left .\" double quote, and \*(R" will give a right double quote. \*(C+ will .\" give a nicer C++. Capital omega is used to do unbreakable dashes and .\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, .\" nothing in troff, for use with C<>. .tr \(*W- .ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' .ie n \{\ . ds -- \(*W- . ds PI pi . if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch . if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch . ds L" "" . ds R" "" . ds C` "" . ds C' "" 'br\} .el\{\ . ds -- \|\(em\| . ds PI \(*p . ds L" `` . ds R" '' . ds C` . ds C' 'br\} .\" .\" Escape single quotes in literal strings from groff's Unicode transform. .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" .\" If the F register is >0, we'll generate index entries on stderr for .\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index .\" entries marked with X<> in POD. Of course, you'll have to process the .\" output yourself in some meaningful fashion. .\" .\" Avoid warning from groff about undefined register 'F'. .de IX .. .nr rF 0 .if \n(.g .if rF .nr rF 1 .if (\n(rF:(\n(.g==0)) \{\ . if \nF \{\ . de IX . tm Index:\\$1\t\\n%\t"\\$2" .. . if !\nF==2 \{\ . nr % 0 . nr F 2 . \} . \} .\} .rr rF .\" ======================================================================== .\" .IX Title "Test::HTML::Content 3pm" .TH Test::HTML::Content 3pm "2023-07-29" "perl v5.36.0" "User Contributed Perl Documentation" .\" For nroff, turn off justification. Always turn off hyphenation; it makes .\" way too many mistakes in technical documents. .if n .ad l .nh .SH "NAME" Test::HTML::Content \- Perl extension for testing HTML output .SH "SYNOPSIS" .IX Header "SYNOPSIS" .Vb 1 \& use Test::HTML::Content( tests => 13 ); .Ve .PP .Vb 5 \& $HTML = "A test page

Home page

\& \*(Aqcamel\*(Aq \& Perl \& \*(Aqmore \& "; \& \& 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]+\e.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\*(Aqugly$\*(Aq }, "No ugly styles" ); \& \& # REs also can be used for substrings in comments \& comment_ok($HTML,qr"[hH]idden\es+mess"); \& \& # and if you have XML::LibXML or XML::XPath, you can \& # even do XPath queries yourself: \& xpath_ok($HTML,\*(Aq/html/body/p\*(Aq,\*(AqHTML is somewhat wellformed\*(Aq); \& no_xpath($HTML,\*(Aq/html/head/p\*(Aq,\*(AqHTML is somewhat wellformed\*(Aq); .Ve .SH "DESCRIPTION" .IX Header "DESCRIPTION" This is a module to test the \s-1HTML\s0 output of your programs in simple test scripts. It can test a scalar (presumably containing \s-1HTML\s0) for the presence (or absence, or a specific number) of tags having (or lacking) specific attributes. Unspecified attributes are ignored, and the attribute values can be specified as either scalars (meaning a match succeeds if the strings are identical) or regular expressions (meaning that a match succeeds if the actual attribute value is matched by the given \s-1RE\s0) or undef (meaning that the attribute must not be present). .PP If you want to specify or test the deeper structure of the \s-1HTML\s0 (for example, \s-1META\s0 tags within the \s-1BODY\s0) or the (textual) content of tags, you will have to resort to \f(CW\*(C`xpath_ok\*(C'\fR,\f(CW\*(C`xpath_count\*(C'\fR and \f(CW\*(C`no_xpath\*(C'\fR, which take an XPath expression. If you find yourself crafting very complex XPath expression to verify the structure of your output, it is time to rethink your testing process and maybe use a template based solution or simply compare against prefabricated files as a whole. .PP The used \s-1HTML\s0 parser is HTML::TokeParser, the used XPath module is XML::XPath or XML::LibXML. XML::XPath needs valid xHTML, XML::LibXML will try its best to force your code into xHTML, but it is best to supply valid xHTML (snippets) to the test functions. .PP 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. The module then 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. .PP The test functionality is derived from Test::Builder, and the export behaviour is the same. When you use Test::HTML::Content, a set of \&\s-1HTML\s0 testing functions is exported into the namespace of the caller. .SS "\s-1EXPORT\s0" .IX Subsection "EXPORT" Exports the bunch of test functions : .PP .Vb 6 \& 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() .Ve .SS "\s-1CONSIDERATIONS\s0" .IX Subsection "CONSIDERATIONS" The module reparses the \s-1HTML\s0 string every time a test function is called. This will make running many tests over the same, large \s-1HTML\s0 stream relatively slow. A possible speedup could be simple minded caching mechanism that keeps the most recent \s-1HTML\s0 stream in a cache. .SS "\s-1CAVEATS\s0" .IX Subsection "CAVEATS" The test output differs between XPath and \s-1HTML\s0 parsing, because XML::XPath delivers the complete node including the content, where my \s-1HTML\s0 parser only delivers the start tag. So don't make your tests depend on the _exact_ output of my tests. It was a pain to do so in my test scripts for this module and if you really want to, take a look at the included test scripts. .PP The title functions \f(CW\*(C`title_ok\*(C'\fR and \f(CW\*(C`no_title\*(C'\fR rely on the XPath functionality and will thus skip if XPath functionality is unavailable. .SS "\s-1BUGS\s0" .IX Subsection "BUGS" Currently, if there is text split up by comments, the text will be seen as two separate entities, so the following dosen't work : .PP .Vb 1 \& is_text( "Hello World", "Hello World" ); .Ve .PP Whether this is a real bug or not, I don't know at the moment \- most likely, I'll modify \fBtext_ok()\fR and siblings to ignore embedded comments. .SS "\s-1TODO\s0" .IX Subsection "TODO" My things on the todo list for this module. Patches are welcome ! .IP "\(bu" 4 Refactor the code to fold some of the internal routines .IP "\(bu" 4 Implement a cache for the last parsed tree / token sequence .IP "\(bu" 4 Possibly \fBdiag()\fR the row/line number for failing tests .IP "\(bu" 4 Allow \s-1RE\s0 instead of plain strings in the functions (for tags themselves). This one is most likely useless. .SH "LICENSE" .IX Header "LICENSE" This code may be distributed under the same terms as Perl itself. .SH "AUTHOR" .IX Header "AUTHOR" Max Maischein .SH "SEE ALSO" .IX Header "SEE ALSO" \&\fBperl\fR\|(1), Test::Builder,Test::Simple,Test::HTML::Lint.