Add Cookie attributes + SameSite CookieResultMatchers in MockMvc
This commit adds assertions to MockMvc's CookieresultMatchers: - `attribute` for arbitrary attributes - `sameSite` for the SameSite well-known attribute Note that the `sameSite` methods delegate to their `attribute` counterparts. Note also that Jakarta's `Cookie#getAttribute` method is case-insensitive, which is reflected in the documentation of the `attribute` assertion method and the tests. Closes gh-30285
This commit is contained in:
parent
842490beeb
commit
d6460e0d57
|
|
@ -146,6 +146,24 @@ public class CookieResultMatchers {
|
|||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert a cookie's SameSite attribute with a Hamcrest {@link Matcher}.
|
||||
* @since 6.0.8
|
||||
* @see #attribute(String, String, Matcher)
|
||||
*/
|
||||
public ResultMatcher sameSite(String name, Matcher<? super String> matcher) {
|
||||
return attribute(name, "SameSite", matcher);
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert a cookie's SameSite attribute.
|
||||
* @since 6.0.8
|
||||
* @see #attribute(String, String, String)
|
||||
*/
|
||||
public ResultMatcher sameSite(String name, String sameSite) {
|
||||
return attribute(name, "SameSite", sameSite);
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert a cookie's comment with a Hamcrest {@link Matcher}.
|
||||
*/
|
||||
|
|
@ -211,6 +229,34 @@ public class CookieResultMatchers {
|
|||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert a cookie's specified attribute with a Hamcrest {@link Matcher}.
|
||||
* @param cookieAttribute the name of the Cookie attribute (case-insensitive)
|
||||
* @since 6.0.8
|
||||
*/
|
||||
public ResultMatcher attribute(String cookieName, String cookieAttribute, Matcher<? super String> matcher) {
|
||||
return result -> {
|
||||
Cookie cookie = getCookie(result, cookieName);
|
||||
String attribute = cookie.getAttribute(cookieAttribute);
|
||||
assertNotNull("Response cookie '" + cookieName + "' doesn't have attribute '" + cookieAttribute + "'", attribute);
|
||||
assertThat("Response cookie '" + cookieName + "' attribute '" + cookieAttribute + "'",
|
||||
attribute, matcher);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert a cookie's specified attribute.
|
||||
* @param cookieAttribute the name of the Cookie attribute (case-insensitive)
|
||||
* @since 6.0.8
|
||||
*/
|
||||
public ResultMatcher attribute(String cookieName, String cookieAttribute, String attributeValue) {
|
||||
return result -> {
|
||||
Cookie cookie = getCookie(result, cookieName);
|
||||
assertEquals("Response cookie '" + cookieName + "' attribute '" + cookieAttribute + "'",
|
||||
attributeValue, cookie.getAttribute(cookieAttribute));
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
private static Cookie getCookie(MvcResult result, String name) {
|
||||
Cookie cookie = result.getResponse().getCookie(name);
|
||||
|
|
|
|||
|
|
@ -99,6 +99,20 @@ class CookieResultMatchersDsl internal constructor (private val actions: ResultA
|
|||
actions.andExpect(matchers.domain(name, domain))
|
||||
}
|
||||
|
||||
/**
|
||||
* @see CookieResultMatchers.sameSite
|
||||
*/
|
||||
fun sameSite(name: String, matcher: Matcher<String>) {
|
||||
actions.andExpect(matchers.sameSite(name, matcher))
|
||||
}
|
||||
|
||||
/**
|
||||
* @see CookieResultMatchers.sameSite
|
||||
*/
|
||||
fun sameSite(name: String, sameSite: String) {
|
||||
actions.andExpect(matchers.sameSite(name, sameSite))
|
||||
}
|
||||
|
||||
/**
|
||||
* @see CookieResultMatchers.comment
|
||||
*/
|
||||
|
|
@ -140,4 +154,18 @@ class CookieResultMatchersDsl internal constructor (private val actions: ResultA
|
|||
fun httpOnly(name: String, httpOnly: Boolean) {
|
||||
actions.andExpect(matchers.httpOnly(name, httpOnly))
|
||||
}
|
||||
|
||||
/**
|
||||
* @see CookieResultMatchers.attribute
|
||||
*/
|
||||
fun attribute(name: String, attributeName: String, matcher: Matcher<String>) {
|
||||
actions.andExpect(matchers.attribute(name, attributeName, matcher))
|
||||
}
|
||||
|
||||
/**
|
||||
* @see CookieResultMatchers.attribute
|
||||
*/
|
||||
fun attribute(name: String, attributeName: String, attributeValue: String) {
|
||||
actions.andExpect(matchers.attribute(name, attributeName, attributeValue))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,15 +16,22 @@
|
|||
|
||||
package org.springframework.test.web.servlet.samples.standalone.resultmatchers;
|
||||
|
||||
import jakarta.servlet.http.Cookie;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.servlet.HandlerInterceptor;
|
||||
import org.springframework.web.servlet.i18n.CookieLocaleResolver;
|
||||
import org.springframework.web.servlet.i18n.LocaleChangeInterceptor;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
import static org.hamcrest.CoreMatchers.anything;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.startsWith;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
|
|
@ -41,6 +48,8 @@ import static org.springframework.test.web.servlet.setup.MockMvcBuilders.standal
|
|||
public class CookieAssertionTests {
|
||||
|
||||
private static final String COOKIE_NAME = CookieLocaleResolver.DEFAULT_COOKIE_NAME;
|
||||
private static final String COOKIE_WITH_ATTRIBUTES_NAME = "SecondCookie";
|
||||
protected static final String SECOND_COOKIE_ATTRIBUTE = "COOKIE_ATTRIBUTE";
|
||||
|
||||
private MockMvc mockMvc;
|
||||
|
||||
|
|
@ -50,9 +59,21 @@ public class CookieAssertionTests {
|
|||
CookieLocaleResolver localeResolver = new CookieLocaleResolver();
|
||||
localeResolver.setCookieDomain("domain");
|
||||
localeResolver.setCookieHttpOnly(true);
|
||||
localeResolver.setCookieSameSite("foo");
|
||||
|
||||
Cookie cookie = new Cookie(COOKIE_WITH_ATTRIBUTES_NAME, "value");
|
||||
cookie.setAttribute("sameSite", "Strict"); //intentionally camelCase
|
||||
cookie.setAttribute(SECOND_COOKIE_ATTRIBUTE, "there");
|
||||
|
||||
this.mockMvc = standaloneSetup(new SimpleController())
|
||||
.addInterceptors(new LocaleChangeInterceptor())
|
||||
.addInterceptors(new HandlerInterceptor() {
|
||||
@Override
|
||||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
|
||||
response.addCookie(cookie);
|
||||
return true;
|
||||
}
|
||||
})
|
||||
.setLocaleResolver(localeResolver)
|
||||
.defaultRequest(get("/").param("locale", "en_US"))
|
||||
.alwaysExpect(status().isOk())
|
||||
|
|
@ -91,6 +112,26 @@ public class CookieAssertionTests {
|
|||
this.mockMvc.perform(get("/")).andExpect(cookie().domain(COOKIE_NAME, "domain"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSameSite() throws Exception {
|
||||
this.mockMvc.perform(get("/")).andExpect(cookie()
|
||||
.sameSite(COOKIE_NAME, "foo"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSameSiteMatcher() throws Exception {
|
||||
this.mockMvc.perform(get("/")).andExpect(cookie()
|
||||
.sameSite(COOKIE_WITH_ATTRIBUTES_NAME, startsWith("Str")));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSameSiteNotEquals() throws Exception {
|
||||
assertThatExceptionOfType(AssertionError.class).isThrownBy(() ->
|
||||
this.mockMvc.perform(get("/")).andExpect(cookie()
|
||||
.sameSite(COOKIE_WITH_ATTRIBUTES_NAME, "Str")))
|
||||
.withMessage("Response cookie 'SecondCookie' attribute 'SameSite' expected:<Str> but was:<Strict>");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVersion() throws Exception {
|
||||
this.mockMvc.perform(get("/")).andExpect(cookie().version(COOKIE_NAME, 0));
|
||||
|
|
@ -111,6 +152,32 @@ public class CookieAssertionTests {
|
|||
this.mockMvc.perform(get("/")).andExpect(cookie().httpOnly(COOKIE_NAME, true));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testAttribute() throws Exception {
|
||||
this.mockMvc.perform(get("/")).andExpect(cookie()
|
||||
.attribute(COOKIE_WITH_ATTRIBUTES_NAME, SECOND_COOKIE_ATTRIBUTE, "there"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testAttributeMatcher() throws Exception {
|
||||
this.mockMvc.perform(get("/")).andExpect(cookie()
|
||||
.attribute(COOKIE_WITH_ATTRIBUTES_NAME, SECOND_COOKIE_ATTRIBUTE, is("there")));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testAttributeNotPresent() {
|
||||
assertThatExceptionOfType(AssertionError.class).isThrownBy(() -> this.mockMvc.perform(get("/"))
|
||||
.andExpect(cookie().attribute(COOKIE_WITH_ATTRIBUTES_NAME, "randomAttribute", anything())))
|
||||
.withMessage("Response cookie 'SecondCookie' doesn't have attribute 'randomAttribute'");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testAttributeNotEquals() {
|
||||
assertThatExceptionOfType(AssertionError.class).isThrownBy(() -> this.mockMvc.perform(get("/"))
|
||||
.andExpect(cookie().attribute(COOKIE_WITH_ATTRIBUTES_NAME, SECOND_COOKIE_ATTRIBUTE, "foo")))
|
||||
.withMessage("Response cookie 'SecondCookie' attribute 'COOKIE_ATTRIBUTE' expected:<foo> but was:<there>");
|
||||
}
|
||||
|
||||
|
||||
@Controller
|
||||
private static class SimpleController {
|
||||
|
|
|
|||
Loading…
Reference in New Issue