How to test a Anchor click if its target is a resource in UI unit tests

Hi,
in V24.3 I’m try to verify that a click on a download link (Anchor) calls the download service. However, since the Anchor target is a resource, it doesn’t seem to work, it throws an exception when using anchorTester.click().
How do I test that the download service is called on anchor click?

private Anchor createDownloadAnchor() {
    var anchor = new Anchor(
           new StreamResource("myfiles.zip", this::onDownload), "");
    anchor.getElement().setAttribute("download", true);
    anchor.setId("download");

    var button = new Button("Download My files");
    button.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
    anchor.add(button);

    return anchor;
}
void test() {
    var anchor = view.find(Anchor.class)
                .id("download");
    when(downloadService.download()).thenReturn(InputStream.nullInputStream());
    test(anchor).click();
    verify(downloadService).download();
}

throws:
java.lang.IllegalStateException: Anchor target seems to be a resource

Feels like a missing feature? As a workaround, maybe you can catch the exception and check that it contains that specific message.

This seems more like a Junit/Mockito question than a Vaadin one. I think the right way is to mock DownloadService then verify the call.

Doesn’t help with getting the required test coverage :grinning:

Junit / Mockito is not at fault here, but yes, that’s exactly what I’m trying to do - to verify that service is invoked. DownloadService is already mocked, it’s just that test(anchor).click(); results in IllegalStateException, it doesn’t get to calling downloadService.

Ok. Your code did not show the mocking so I assumed that was the problem. Good luck with finding a solution.

Managed to solve this with a custom tester that reproduces the internal logic that happens when downloading a file:

@Tests({ Anchor.class })
public class DownloadAnchorTester
        extends ComponentTester<Anchor> {

    public DownloadAnchorTester(Anchor component) {
        super(component);
    }

    void download(OutputStream outputStream) {
        var anchor = getComponent();
        var session = VaadinSession.getCurrent();
        var registry = session.getResourceRegistry();

        Optional<AbstractStreamResource> maybeResource = Optional.empty();
        try {
            maybeResource = registry.getResource(new URI(anchor.getHref()));
        } catch (URISyntaxException e) {
            // Ignore, throws below if resource is empty
        }

        if (maybeResource.isEmpty()) {
            throw new IllegalStateException(
                    "Anchor does not contain a download");
        }

        var streamResource = (StreamResource) maybeResource.get();
        try {
            streamResource.getWriter().accept(outputStream, session);
        } catch (IOException e) {
            throw new RuntimeException("Download failed");
        }
    }
}

Triggering and verifying the download result is then:

var anchorTester = new DownloadAnchorTester(anchor);
var outputStream = new ByteArrayOutputStream();
anchorTester.download(outputStream);
1 Like

Nice, that should do it, thanks!