Skip to content

Commit

Permalink
[plugin-web-app-to-rest-api] Filter invalid jump links from context r…
Browse files Browse the repository at this point in the history
…esource validation
  • Loading branch information
web-flow committed Jan 30, 2024
1 parent ddb95f2 commit d5b6a37
Show file tree
Hide file tree
Showing 5 changed files with 67 additions and 9 deletions.
3 changes: 2 additions & 1 deletion docs/modules/plugins/pages/plugin-web-app-to-rest-api.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -389,7 +389,8 @@ a|Reasons:

* the resource path matches the patterns specified by the `resource-checker.uri-to-ignore-regex` property;
* the resource path is equal to `#` (anchor);
* the resource is not a HTTP(S) resource.
* the resource is not a HTTP(S) resource;
* the resource is jump link which cannot be verified from the current context (if only part of the document is checked).

|`SKIPPED`
|A resource validation has already been performed, i.e. if the same resource might be present on several pages so we do not need to validate it twice.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,24 @@ public enum HtmlLocatorType
this.finder = finder;
}

public Document getDocument(String html, String baseUri)
{
return Jsoup.parse(html, baseUri);
}

public Elements findElements(Document document, String locator)
{
return finder.apply(document, locator);
}

public Elements findElements(String html, String locator)
{
return findElements("", html, locator);
return findElements(getDocument(html, ""), locator);
}

public Elements findElements(String baseUri, String html, String locator)
{
return finder.apply(Jsoup.parse(html, baseUri), locator);
return findElements(getDocument(html, baseUri), locator);
}

public String getDescription()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
import org.apache.hc.core5.net.URIBuilder;
import org.jbehave.core.annotations.Then;
import org.jbehave.core.model.ExamplesTable;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Selector.SelectorParseException;
import org.vividus.html.HtmlLocatorType;
Expand All @@ -56,6 +57,7 @@ public class ResourceCheckSteps
private static final Set<String> ALLOWED_SCHEMES = Set.of("http", "https");
private static final String URL_FRAGMENT = "#";
private static final String HREF_ATTR = "href";
private static final String HTML_TITLE_TAG = "title";

private final ResourceValidator<WebPageResourceValidation> resourceValidator;
private final AttachmentPublisher attachmentPublisher;
Expand Down Expand Up @@ -106,7 +108,9 @@ public void checkResources(HtmlLocatorType htmlLocatorType, String htmlLocator,
{
softAssert.runIgnoringTestFailFast(() -> execute(() ->
{
Collection<Element> resourcesToValidate = htmlLocatorType.findElements(html, htmlLocator);
Document document = htmlLocatorType.getDocument(html, "");
Collection<Element> resourcesToValidate = htmlLocatorType.findElements(document, htmlLocator);
boolean contextCheck = document.head().getElementsByTag(HTML_TITLE_TAG).isEmpty();
Stream<WebPageResourceValidation> validations = createResourceValidations(resourcesToValidate,
resourceValidation -> {
URI uriToCheck = resourceValidation.getUriOrError().getLeft();
Expand All @@ -120,7 +124,7 @@ public void checkResources(HtmlLocatorType htmlLocatorType, String htmlLocator,
resourceValidation.setError(message);
resourceValidation.setCheckStatus(CheckStatus.BROKEN);
}
});
}, contextCheck);
validateResources(validations);
}));
}
Expand All @@ -140,17 +144,17 @@ private WebPageResourceValidation validate(WebPageResourceValidation r)
}

private Stream<WebPageResourceValidation> createResourceValidations(Collection<Element> elements,
Consumer<WebPageResourceValidation> resourceValidator)
Consumer<WebPageResourceValidation> resourceValidator, boolean contextCheck)
{
return elements.stream()
.map(this::parseElement)
.map(e -> parseElement(e, contextCheck))
.filter(Optional::isPresent)
.map(Optional::get)
.peek(resourceValidator)
.parallel();
}

private Optional<WebPageResourceValidation> parseElement(Element element)
private Optional<WebPageResourceValidation> parseElement(Element element, boolean contextCheck)
{
String elementUriAsString = getElementUri(element).trim();
if (elementUriAsString.startsWith("data:"))
Expand Down Expand Up @@ -186,6 +190,15 @@ private Optional<WebPageResourceValidation> parseElement(Element element)
&& root.getElementsByAttributeValue("name", fragment).isEmpty();
if (targetNotPresent)
{
if (contextCheck)
{
WebPageResourceValidation contextJumpLinkValidation = new WebPageResourceValidation(
Pair.of(null, String.format(
"Jump link with the target \"%s\" cannot be verified from the current context",
elementUriAsString)), elementCssSelector);
contextJumpLinkValidation.setCheckStatus(CheckStatus.FILTERED);
return Optional.of(contextJumpLinkValidation);
}
return Optional.of(ResourceValidationError.MISSING_JUMPLINK_TARGET
.onAssertion(softAssert::recordFailedAssertion, elementCssSelector, fragment)
.createValidation(null, elementCssSelector, fragment));
Expand Down Expand Up @@ -321,7 +334,7 @@ public void checkResources(HtmlLocatorType htmlLocatorType, String htmlLocator,
return Optional.ofNullable(httpTestContext.getResponse().getResponseBodyAsString())
.map(response -> htmlLocatorType.findElements(pageUrl, response, htmlLocator))
.map(elements -> createResourceValidations(elements,
rV -> rV.setPageURL(pageUrl)
rV -> rV.setPageURL(pageUrl), false
))
.orElseGet(() -> Stream.of(createMissingPageBodyValidation(pageUrl)));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -573,6 +573,36 @@ void shouldFilterResourceByRegExpCheckDesiredResourcesAnPostAttachment()
}), eq(REPORT_NAME));
}

@Test
void shouldFilterJumpLinkDuringContextValidation() throws InterruptedException, ExecutionException
{
String contextHtml = "<a id='jump-link' href='#section'>Jump link</a>";
mockResourceValidator();
runExecutor();
resourceCheckSteps.setUriToIgnoreRegex(Optional.empty());
resourceCheckSteps.init();
resourceCheckSteps.checkResources(HtmlLocatorType.CSS_SELECTOR, LINK_SELECTOR, contextHtml);

verify(attachmentPublisher).publishAttachment(eq(TEMPLATE_NAME), argThat(m -> {
@SuppressWarnings(UNCHECKED)
Set<WebPageResourceValidation> validationsToReport = ((Map<String, Set<WebPageResourceValidation>>) m)
.get(RESULTS);
Iterator<WebPageResourceValidation> resourceValidations = validationsToReport.iterator();
WebPageResourceValidation validation = resourceValidations.next();
Pair<URI, String> uriOrError = validation.getUriOrError();

Assertions.assertAll(
() -> assertNull(uriOrError.getLeft()),
() -> assertEquals(
"Jump link with the target \"#section\" cannot be verified from the current context",
uriOrError.getRight()),
() -> assertEquals(JUMP_LINK_SELECTOR, validation.getCssSelector()),
() -> assertSame(CheckStatus.FILTERED, validation.getCheckStatus()),
() -> assertEquals(N_A, validation.getPageURL()));
return true;
}), eq(REPORT_NAME));
}

private void runExecutor() throws InterruptedException, ExecutionException
{
doNothing().when(executor).execute(argThat(r -> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ Given I am on page with URL `<pageToValidate>`
Then all resources found by xpath `//a[@href]` in ${${source-code}} are valid
!-- Deprecated
Then all resources by selector `a[href]` from ${source-code} are valid
When I change context to element located by `linkText(Link with tooltip)`
Then all resources by selector `a[href]` from ${context-source-code} are valid

Scenario: Verification of the jump link from context
When I change context to element located by `linkText(Link to unexistent element)`
Then all resources by selector `a[href]` from ${context-source-code} are valid

Expand Down

0 comments on commit d5b6a37

Please # to comment.