001package de.cuioss.test.jsf.util;
002
003import static de.cuioss.tools.string.MoreStrings.emptyToNull;
004import static org.junit.jupiter.api.Assertions.assertEquals;
005import static org.junit.jupiter.api.Assertions.assertNotNull;
006import static org.junit.jupiter.api.Assertions.assertTrue;
007
008import javax.faces.application.Application;
009import javax.faces.application.NavigationHandler;
010import javax.faces.context.ExternalContext;
011import javax.faces.context.FacesContext;
012import javax.servlet.http.HttpServletResponse;
013
014import org.apache.myfaces.test.mock.MockHttpServletResponse;
015import org.junit.jupiter.api.extension.TestInstancePostProcessor;
016
017import de.cuioss.test.jsf.config.JsfTestContextConfigurator;
018import de.cuioss.test.jsf.config.decorator.ApplicationConfigDecorator;
019import de.cuioss.test.jsf.config.decorator.BeanConfigDecorator;
020import de.cuioss.test.jsf.config.decorator.ComponentConfigDecorator;
021import de.cuioss.test.jsf.config.decorator.RequestConfigDecorator;
022import de.cuioss.test.jsf.junit5.JsfSetupExtension;
023
024/**
025 * Simple interface to be used in context of {@link JsfSetupExtension}. It
026 * provides an interface for injecting the configured
027 * {@link JsfEnvironmentHolder}. It is needed, when the test needs to access
028 * either an {@link JsfTestContextConfigurator} like
029 * {@link ComponentConfigDecorator} or {@link RequestConfigDecorator} or a
030 * JSF-Object like {@link FacesContext} or {@link Application} programmatically.
031 * The typical usage:
032 *
033 * <pre>
034 * <code>
035    &#64;Setter
036    &#64;Getter
037    private JsfEnvironmentHolder environmentHolder;
038 * </code>
039 *
040 * </pre>
041 *
042 * The actual delegation is implemented using default implementations within
043 * this interface, see the unit-test:
044 *
045 * <pre>
046 * <code>
047&#64;EnableJsfEnvironment
048&#64;JsfTestConfiguration(BasicApplicationConfiguration.class)
049class JsfSetupExtensionTest implements JsfEnvironmentConsumer {
050
051    &#64;Setter
052    &#64;Getter
053    private JsfEnvironmentHolder environmentHolder;
054
055    &#64;Test
056    void shouldBootstrapJsf() {
057        assertNotNull(environmentHolder);
058        assertNotNull(getApplication());
059        assertNotNull(getApplicationConfigDecorator());
060        assertNotNull(getBeanConfigDecorator());
061        assertNotNull(getComponentConfigDecorator());
062        assertNotNull(getExternalContext());
063        assertNotNull(getFacesContext());
064        assertNotNull(getRequestConfigDecorator());
065        assertNotNull(getResponse());
066    }
067
068    &#64;Test
069    void shouldApplyBasicConfiguration() {
070        assertEquals(BasicApplicationConfiguration.FIREFOX,
071                getExternalContext().getRequestHeaderMap().get(BasicApplicationConfiguration.USER_AGENT));
072    }
073 * </code>
074 * </pre>
075 *
076 * @author Oliver Wolff
077 *
078 */
079public interface JsfEnvironmentConsumer {
080
081    /**
082     * @param holder to be set, is never null. Will be called from
083     *               {@link TestInstancePostProcessor#postProcessTestInstance(Object, org.junit.jupiter.api.extension.ExtensionContext)}
084     */
085    void setEnvironmentHolder(JsfEnvironmentHolder holder);
086
087    /**
088     * @return holder set by {@link #setEnvironmentHolder(JsfEnvironmentHolder)}
089     */
090    JsfEnvironmentHolder getEnvironmentHolder();
091
092    /**
093     * @return an {@link ComponentConfigDecorator} for the contained
094     *         {@link JsfEnvironmentHolder}
095     */
096    default ComponentConfigDecorator getComponentConfigDecorator() {
097        return getEnvironmentHolder().getComponentConfigDecorator();
098    }
099
100    /**
101     * @return an {@link BeanConfigDecorator} for the contained
102     *         {@link JsfEnvironmentHolder}
103     */
104    default BeanConfigDecorator getBeanConfigDecorator() {
105        return getEnvironmentHolder().getBeanConfigDecorator();
106    }
107
108    /**
109     * @return an {@link ApplicationConfigDecorator} for the contained
110     *         {@link JsfEnvironmentHolder}
111     */
112    default ApplicationConfigDecorator getApplicationConfigDecorator() {
113        return getEnvironmentHolder().getApplicationConfigDecorator();
114    }
115
116    /**
117     * @return an {@link ApplicationConfigDecorator} for the contained
118     *         {@link JsfEnvironmentHolder}
119     */
120    default RequestConfigDecorator getRequestConfigDecorator() {
121        return getEnvironmentHolder().getRequestConfigDecorator();
122    }
123
124    /**
125     * @return an {@link FacesContext} for the contained
126     *         {@link JsfEnvironmentHolder}
127     */
128    default FacesContext getFacesContext() {
129        return getEnvironmentHolder().getFacesContext();
130    }
131
132    /**
133     * @return an {@link Application} for the contained {@link JsfEnvironmentHolder}
134     */
135    default Application getApplication() {
136        return getEnvironmentHolder().getApplication();
137    }
138
139    /**
140     * @return an {@link ExternalContext} for the contained
141     *         {@link JsfEnvironmentHolder}
142     */
143    default ExternalContext getExternalContext() {
144        return getEnvironmentHolder().getExternalContext();
145    }
146
147    /**
148     * @return an {@link MockHttpServletResponse} for the contained
149     *         {@link JsfEnvironmentHolder}
150     */
151    default MockHttpServletResponse getResponse() {
152        return getEnvironmentHolder().getResponse();
153    }
154
155    /**
156     * Asserts whether a navigation was handled by calling
157     * {@link NavigationHandler#handleNavigation(javax.faces.context.FacesContext, String, String)}
158     *
159     * @param outcome must not be null
160     */
161    default void assertNavigatedWithOutcome(final String outcome) {
162        assertNotNull(emptyToNull(outcome), "Outcome must not be null");
163        assertTrue(getFacesContext().getExternalContext().isResponseCommitted(), "Response is not committed");
164        var handler = getApplicationConfigDecorator().getMockNavigationHandler();
165        assertTrue(handler.isHandleNavigationCalled(), "handleNavigation is not called");
166        assertEquals(outcome, handler.getCalledOutcome());
167    }
168
169    /**
170     * Asserts whether a navigation was initialized by calling
171     * {@link ExternalContext#redirect(String)}
172     *
173     * @param redirectUrl must not be null
174     */
175    default void assertRedirect(final String redirectUrl) {
176        assertNotNull(emptyToNull(redirectUrl), "redirectUrl must not be null");
177        assertTrue(getFacesContext().getExternalContext().isResponseCommitted(), "Response is not committed");
178        var tempResponse = (HttpServletResponse) getExternalContext().getResponse();
179        assertTrue(tempResponse.containsHeader("Location"), "Response must provide a header with the name 'Location'");
180        assertEquals(redirectUrl, tempResponse.getHeader("Location"));
181    }
182}