Skip to content

HtmlUnitRequestBuilder ignores file uploaded via HtmlFileInput.setData() #27199

@svschouw-bb

Description

@svschouw-bb

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.

Metadata

Metadata

Assignees

Labels

in: testIssues in the test modulein: webIssues in web modules (web, webmvc, webflux, websocket)type: bugA general bug

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions