package de.escalon.hypermedia.spring.xhtml;
import de.escalon.hypermedia.action.Select;
import de.escalon.hypermedia.spring.sample.test.DummyEventController;
import de.escalon.hypermedia.spring.sample.test.ReviewController;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
import static org.springframework.test.web.servlet.setup.MockMvcBuilders.webAppContextSetup;
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration
public class XhtmlResourceMessageConverterTest {
public static final Logger LOG = LoggerFactory.getLogger(XhtmlResourceMessageConverterTest.class);
@Autowired
private WebApplicationContext wac;
private MockMvc mockMvc;
private static Map<String, String> namespaces = new HashMap<String, String>();
static {
namespaces.put("h", "http://www.w3.org/1999/xhtml");
}
@Configuration
@EnableWebMvc
static class WebConfig extends WebMvcConfigurerAdapter {
@Bean
public ReviewController reviewController() {
return new ReviewController();
}
@Bean
public DummyEventController eventController() {
return new DummyEventController();
}
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
super.configureMessageConverters(converters);
converters.add(new XhtmlResourceMessageConverter());
}
@Override
public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) {
final ExceptionHandlerExceptionResolver resolver = new ExceptionHandlerExceptionResolver();
resolver.setWarnLogCategory(resolver.getClass()
.getName());
exceptionResolvers.add(resolver);
}
}
@Before
public void setup() {
this.mockMvc = webAppContextSetup(this.wac).build();
}
@Test
public void testCreatesHtmlFormForGet() throws Exception {
MvcResult result = this.mockMvc.perform(get("http://localhost/events").accept(MediaType.TEXT_HTML))
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.TEXT_HTML))
.andExpect(xpath("//h:form[@action='http://localhost/events' and @method='GET' and " +
"@name='findEventByName']", namespaces).exists())
// TODO: form name
.andExpect(xpath("//h:form[@action='http://localhost/events' and @method='GET' and " +
"@name='findEventByName']/h:div/h:input/@name",
namespaces).string("eventName"))
.andReturn();
LOG.debug(result.getResponse()
.getContentAsString());
}
@Test
public void testCreatesSimpleLinkForGetAffordanceWithoutRequestParams() throws Exception {
MvcResult result = this.mockMvc.perform(get("/events").accept(MediaType.TEXT_HTML))
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.TEXT_HTML))
.andExpect(xpath("//h:a[@href='http://localhost/events/1']", namespaces).exists())
.andExpect(xpath("//h:a[@href='http://localhost/events/2']", namespaces).exists())
.andReturn();
LOG.debug(result.getResponse()
.getContentAsString());
}
@Test
public void testCreatesHtmlFormForPost() throws Exception {
MvcResult result = this.mockMvc.perform(get("/events").accept(MediaType.TEXT_HTML))
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.TEXT_HTML))
.andExpect(xpath("//h:form[@name='addEvent']/@action", namespaces).string("http://localhost/events"))
.andExpect(xpath("//h:form[@name='addEvent']/@method", namespaces).string("POST"))
.andExpect(xpath("//h:form[@name='addEvent']/h:div/h:select[@name='eventStatus']", namespaces).exists())
.andExpect(xpath("//h:form[@name='addEvent']/h:div/h:select[@name='typicalAgeRange']", namespaces)
.exists())
.andReturn();
LOG.debug(result.getResponse()
.getContentAsString());
}
@Test
public void testCreatesHtmlFormForPut() throws Exception {
// TODO too many divs
// TODO GET form without input
// TODO GET iritemplate form has no name
MvcResult result = this.mockMvc.perform(get("/events").accept(MediaType.TEXT_HTML))
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.TEXT_HTML))
.andExpect(xpath("//h:form[@name='updateEventWithRequestBody']/@action", namespaces).string
("http://localhost/events/1"))
.andExpect(xpath("//h:form[@name='updateEventWithRequestBody']/h:input[@name='_method']/@value",
namespaces).string("PUT"))
.andReturn();
LOG.debug(result.getResponse()
.getContentAsString());
}
@Test
public void testCreatesInputFieldWithMinMaxNumber() throws Exception {
MvcResult result = this.mockMvc.perform(get("/events").accept(MediaType.TEXT_HTML))
.andExpect(status().isOk())
.andExpect(MockMvcResultMatchers.content()
.contentType(MediaType.TEXT_HTML))
.andExpect(xpath("//h:input[@name='reviewRating.ratingValue']", namespaces).exists())
.andExpect(xpath("//h:input[@name='reviewRating.ratingValue']/@type", namespaces).string("number"))
.andExpect(xpath("//h:input[@name='reviewRating.ratingValue']/@min", namespaces).string("1"))
.andExpect(xpath("//h:input[@name='reviewRating.ratingValue']/@max", namespaces).string("5"))
.andExpect(xpath("//h:input[@name='reviewRating.ratingValue']/@value", namespaces).string("3"))
.andReturn();
LOG.debug(result.getResponse()
.getContentAsString());
}
@Test
public void testCreatesInputFieldWithDefaultText() throws Exception {
MvcResult result = this.mockMvc.perform(get("/events").accept(MediaType.TEXT_HTML))
.andExpect(status().isOk())
.andExpect(MockMvcResultMatchers.content()
.contentType(MediaType.TEXT_HTML))
.andExpect(xpath("//h:input[@name='reviewRating.ratingValue']/@value", namespaces).string("3"))
.andReturn();
LOG.debug(result.getResponse()
.getContentAsString());
}
/**
* Tests if the form contains a personId input field with default value.
*
* @throws Exception
*/
@Test
@Ignore
public void testCreatesHiddenInputField() throws Exception {
this.mockMvc.perform(get("/events").accept(MediaType.TEXT_HTML))
.andExpect(status().isOk())
.andExpect(MockMvcResultMatchers.content()
.contentType(MediaType.TEXT_HTML))
.andExpect(xpath("//h:input[@name='personId']", namespaces).exists())
.andExpect(xpath("//h:input[@name='personId']/@type", namespaces).string("hidden"))
.andExpect(xpath("//h:input[@name='personId']/@value", namespaces).string("123"))
.andExpect(xpath("//h:input[@name='firstname']/@value", namespaces).string("Bilbo"));
}
/**
* Tests if the form contains a select field.
*
* @throws Exception
*/
@Test
public void testCreatesSelectFieldForEnum() throws Exception {
MvcResult result = this.mockMvc.perform(get("/events").accept(MediaType.TEXT_HTML))
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.TEXT_HTML))
.andExpect(xpath("//h:select[@name='eventStatus']", namespaces).exists())
.andExpect(xpath("//h:select[@name='eventStatus']/h:option[1]/text()", namespaces).string
("EVENT_CANCELLED"))
.andExpect(xpath("//h:select[@name='eventStatus']/h:option[2]/text()", namespaces).string
("EVENT_POSTPONED"))
.andExpect(xpath("//h:select[@name='eventStatus']/h:option[3]/text()", namespaces).string
("EVENT_SCHEDULED"))
.andExpect(xpath("//h:select[@name='eventStatus']/h:option[4]/text()", namespaces).string
("EVENT_RESCHEDULED"))
.andExpect(xpath("(//h:select[@name='eventStatus']/h:option)[@selected]/text()", namespaces).string
("EVENT_SCHEDULED"))
.andReturn();
LOG.debug(result.getResponse()
.getContentAsString());
}
/**
* Tests a list of possible values defined with {@link Select#options()} annotation.
*
* @throws Exception
*/
@Test
public void testCreatesSelectFieldForSelectOptionsBasedPossibleValues() throws Exception {
MvcResult result = this.mockMvc.perform(get("/events").accept(MediaType.TEXT_HTML))
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.TEXT_HTML))
.andExpect(xpath("//h:form[@name='updateEventWithRequestBody']/h:div/h:select[@name='typicalAgeRange" +
"']", namespaces).exists())
.andExpect(xpath("//h:form[@name='updateEventWithRequestBody']/h:div/h:select[@name='typicalAgeRange" +
"']/h:option[1]", namespaces).string("7-10"))
.andExpect(xpath("//h:form[@name='updateEventWithRequestBody']/h:div/h:select[@name='typicalAgeRange" +
"']/h:option[2]", namespaces).string("11-"))
.andReturn();
LOG.debug(result.getResponse()
.getContentAsString());
}
/**
* Tests if the form contains a multiselect field with three preselected items, matching the person having id 123.
*
* @throws Exception
*/
// @Test
// public void testCreatesMultiSelectFieldForEnumArray() throws Exception {
//
// this.mockMvc.perform(get("/people/customer/123/editor").accept(MediaType.TEXT_HTML)).andExpect(status()
// .isOk())
// .andExpect(content().contentType(MediaType.TEXT_HTML))
// .andExpect(xpath("//h:select[@name='sports' and @multiple]", namespaces).exists())
// .andExpect(xpath("//h:select[@name='sports']/h:option", namespaces).nodeCount(Sport.values().length))
// .andExpect(xpath("(//h:select[@name='sports']/h:option)[@selected]", namespaces).nodeCount(3));
// }
//
// /**
// * Tests List<Enum> parameter.
// *
// * @throws Exception
// */
// @Test
// public void testCreatesMultiSelectFieldForEnumList() throws Exception {
//
// this.mockMvc.perform(get("/people/customer/123/editor").accept(MediaType.TEXT_HTML)).andExpect(status()
// .isOk())
// .andExpect(content().contentType(MediaType.TEXT_HTML))
// .andExpect(xpath("//h:select[@name='gadgets' and @multiple]", namespaces).exists())
// .andExpect(xpath("//h:select[@name='gadgets']/h:option", namespaces).nodeCount(Gadget.values()
// .length))
// .andExpect(xpath("(//h:select[@name='gadgets']/h:option)[@selected]", namespaces).nodeCount(0));
// }
// /**
// * Tests List<String> parameter with a list of possible values.
// *
// * @throws Exception
// */
// @Test
// @Ignore
// public void testCreatesMultiSelectFieldForListOfPossibleValuesFixed() throws Exception {
//
// this.mockMvc.perform(get("/people/customerByAttribute").accept(MediaType.TEXT_HTML))
// .andExpect(status().isOk())
// .andExpect(content().contentType(MediaType.TEXT_HTML))
// .andExpect(xpath("//h:select[@name='attr' and @multiple]", namespaces).exists())
// .andExpect(xpath("//h:select[@name='attr']/h:option", namespaces).nodeCount(3))
// .andExpect(xpath("(//h:select[@name='attr']/h:option)[@selected]", namespaces).string("hungry"));
//
// }
//
// /**
// * Tests List<String> parameter with a list of possible values.
// *
// * @throws Exception
// */
// @Test
// @Ignore
// public void testCreatesMultiSelectFieldForListOfPossibleValuesFromSpringBean() throws Exception {
//
// this.mockMvc.perform(get("/people/customer/123/details").accept(MediaType.TEXT_HTML))
// .andExpect(status().isOk())
// .andExpect(content().contentType(MediaType.TEXT_HTML))
// .andExpect(xpath("//h:select[@name='detail' and @multiple]", namespaces).exists())
// .andExpect(xpath("//h:select[@name='detail']/h:option", namespaces).nodeCount(3))
// .andExpect(xpath("(//h:select[@name='detail']/h:option)[1]", namespaces).string("beard"))
// .andExpect(xpath("(//h:select[@name='detail']/h:option)[2]", namespaces).string("afterShave"))
// .andExpect(xpath("(//h:select[@name='detail']/h:option)[3]", namespaces).string("noseHairTrimmer"));
//
// }
//
//
// /**
// * Tests List<String> parameter with a list of numbers.
// *
// * @throws Exception
// */
// @Test
// @Ignore("implement code on demand")
// public void testCreatesOneInputForIntegerListWithInputUpToAny() throws Exception {
//
// this.mockMvc.perform(get("/people/customer/123/numbers").accept(MediaType.TEXT_HTML))
// .andExpect(status().isOk())
// .andExpect(content().contentType(MediaType.TEXT_HTML))
// .andExpect(xpath("//h:input[@name='number']", namespaces).nodeCount(1));
// // expect code-on-demand here
//
// }
}