When testing an application using HtmlUnit, its often useful to use HtmlFileInput.setData(...)
instead of HtmlFileInput.setFiles(...)
in order to not have to generate temporary files. However, when using MockMvcWebClientBuilder
, this doesn't work. The problem is that HtmlUnitRequestBuilder
ignores the data part.
24926 added support for file uploads in HtmlUnitRequestBuilder
, but missed this use case.
Test case:
filesubmit.html:
<!DOCTYPE html>
<html>
<head>
<title>File submission test</title>
</head>
<body>
<form method="POST" action="/filesubmit" enctype="multipart/form-data">
File: <input name="file" type="file"/>
<button type="submit">Submit</button>
</form>
</body>
</html>
FileSubmitController.java:
@Controller
public class FileSubmitController {
@PostMapping("/filesubmit")
public @ResponseBody String handleFileSubmit(@RequestParam(name = "file", required = false) MultipartFile file) {
return file == null ? "unset" : file.getOriginalFilename();
}
}
FileSubmitTest.java:
@WebMvcTest(FileSubmitController.class)
public class FileSubmitTest {
@Autowired
WebClient webClient;
@Test
void testFileSubmitUsingFile() throws FailingHttpStatusCodeException, MalformedURLException, IOException {
HtmlPage page = webClient.getPage("/filesubmit.html");
HtmlFileInput file = page.querySelector("input[type=file]");
file.setContentType("application/json");
file.setFiles(new File("src/test/resources/test.json"));
HtmlButton submit = page.querySelector("button");
Page resultPage = submit.click();
// Succeeds
assertEquals("test.json", resultPage.getWebResponse().getContentAsString());
}
@Test
void testFileSubmitUsingData() throws FailingHttpStatusCodeException, MalformedURLException, IOException {
HtmlPage page = webClient.getPage("/filesubmit.html");
HtmlFileInput file = page.querySelector("input[type=file]");
file.setValueAttribute("test.json");
file.setContentType("application/json");
file.setData("{}".getBytes());
HtmlButton submit = page.querySelector("button");
Page resultPage = submit.click();
// Fails with expected: <test.json> but was: <unset>
assertEquals("test.json", resultPage.getWebResponse().getContentAsString());
}
}
When starting the application normally and changing WebClient
from a mocked version to a normal version using http://localhost:8080/ both tests succeed.
I'm guessing in HtmlUnitRequestBuilder.params(...)
, the else
part should be something like this:
else { // use data
part = new MockPart(pair.getName(), pair.getValue(), pair.getData());
if (pair.getMimeType() == null)
part.getHeaders().setContentType(MediaType.APPLICATION_OCTET_STREAM);
else
part.getHeaders().setContentType(MediaType.valueOf(pair.getMimeType()));
}
I'm not sure if there is a specific edge case to use the old "mimic empty file upload" else case.
Tested using Spring Boot 2.5.2 using Spring WebMVC 5.3.8.
Comment From: sbrannen
I'm not sure if there is a specific edge case to use the old "mimic empty file upload" else case.
I think that use case will still exist, resulting in 3 use cases.
- file is set
- data is set
- neither file nor data is set (empty upload)
Comment From: sbrannen
Related issues:
-
24926
-
26799
Comment From: sbrannen
I'm not sure if there is a specific edge case to use the old "mimic empty file upload" else case.
Well, after diving into the implementation, it turns out you were right about that. 👍
I was able to support both of those use cases in a single else
block. See 8a7c4fc10d60168ebded312e2b02b3a052c46d33 for details.
I would be grateful if you could try out the fix in one of the upcoming 5.3.10 snapshots and let us know if everything works as expected.
Cheers!
Comment From: svschouw-bb
I would be grateful if you could try out the fix in one of the upcoming 5.3.10 snapshots and let us know if everything works as expected.
I'd love to, but I'm not sure how. Where and when will these snapshots be available?
Comment From: sbrannen
I'd love to, but I'm not sure how. Where and when will these snapshots be available?
The 5.3.10 snapshots for spring-test
are available here.
Information on how to consume snapshots can be found here.
Comment From: svschouw-bb
Yes, seems to work! Great!
Comment From: sbrannen
Yes, seems to work! Great!
Awesome!
Thanks for letting us know.