=encoding UTF-8
=head1 NAME
Test2::Tools::DOM - Tools to test HTML/XML-based DOM representations
=head1 SYNOPSIS
use Test2::V0;
use Test2::Tools::DOM;
my $html = <<'HTML';
A test document
Some text
HTML
is $html, dom {
children bag {
item dom { tag 'body' };
item dom { tag 'head' };
end;
};
at 'link[rel=icon]' => dom {
attr href => 'favicon.ico'
};
find '.paragraph' => array {
item dom { text 'Some text' };
end;
};
};
done_testing;
=head1 DESCRIPTION
Test2::Tools::DOM exports a set of testing functions designed to make it
easier to write declarative tests for XML-based DOM representations. This
will most commonly be HTML documents, but it can include other similar types
of documents (eg. SVG images, other XML documents, etc).
=head1 FUNCTIONS
Unless otherwise stated, the functions described in this section are exported
by default by this distribution.
Most of the heavy lifting behind the scenes is done by L, and
most of the functions described below are thin wrappers around the methods
in that class with the same names.
Likewise, several of them support
L
for filtering the elements they will return.
Please refer to L for
additional details.
=head2 dom
dom { ... }
Starts a new DOM testing context. It takes a single block, inside which the
rest of the functions described in this section can be used.
It can be used as the check in any L testing method.
The input can either be a L object, or a string with the text
representation of the DOM, which will be passed to the L
constructor.
For convenience, if the input is at the root node of the DOM tree, it will be
advanced to its first child element, if one exists.
=head2 all_text
all_text CHECK
Takes a check only. Extracts the text content from all descendants of this
element (by calling
L<'all_text' on the Mojo::DOM58 object|Mojo::DOM58/all_text>), and this is
passed to the provided check.
is '
Hello, World!
', dom {
all_text 'Hello, World!'; # OK: includes text in descendants
text 'Hello, '; # OK: use text for the text of this element only
};
=head2 at
at SELECTOR, CHECK
Takes a selector and a check. The selector is used to find the first matching
descendant (by calling L<'at' on the Mojo::DOM58 object|Mojo::DOM58/at>), and
this is passed to the provided check.
The
L
can be used to check whether a given selector matches or not.
is '
', dom {
attr id => 'a'; # OK, we start at #a
at '#b' => dom {
attr id => 'b'; # OK, we've moved to #b
};
at '#c' => DNE; # OK, this element does not exist
# A missing element matches U, F, and DNE
# A present element matches D, T, and E
};
=head2 attr
attr CHECK
attr NAME, CHECK
Takes either a single check, or the name of an attribute and a check.
When called without a name, all attributes are fetched and passed to the
check as a hashref (by calling
L<'attr' on the Mojo::DOM58 object|Mojo::DOM58/attr>), and this is passed to the
provided check.
When called with a name, only the attribute with that name will be read
and passed to the check.
is '', dom {
# Get a hashref with all attributes
# Hashref is then checked using standard Perl logic
attr hash {
field type => 'checkbox';
field name => 'answer';
field value => 42;
field checked => E; # OK: the attribute exists
field checked => U; # OK: the attribute has no value
field checked => F; # OK: undefined is false in Perl-land
end;
};
};
When fetching a single value, the
L
will be interpreted using XML-logic rather than Perl-logic: an attribute
without a value in the DOM will be undefined but true.
is '', dom {
attr type => 'checkbox';
attr name => 'answer';
attr value => 42;
# When fetching individual attributes, checks use XML-logic
attr checked => E; # OK: the attribute exists
attr checked => U; # OK: the attribute has no value, so it's undefined
attr checked => T; # OK: the attribute is present, so it's true
};
=head2 call
call NAME, CHECK
call [ NAME, ARGUMENTS ], CHECK
call CODEREF, CHECK
call_list ...
call_hash ...
I.
Within the test context created by the L keyword the 'call' family of
keywords provided by L can be used to make calls on the
underlying L object as if the test were using the
L