All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.wicket.util.tester.WicketTester Maven / Gradle / Ivy

Go to download

A module that creates a .jar from the classes in wicket, wicket-util and wicket-request modules in order to create a valid OSGi bundle of the wicket framework.

There is a newer version: 10.1.1
Show newest version
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.apache.wicket.util.tester;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;

import javax.servlet.ServletContext;

import junit.framework.AssertionFailedError;

import org.apache.wicket.Component;
import org.apache.wicket.MarkupContainer;
import org.apache.wicket.Page;
import org.apache.wicket.behavior.AbstractAjaxBehavior;
import org.apache.wicket.feedback.ExactLevelFeedbackMessageFilter;
import org.apache.wicket.feedback.FeedbackMessage;
import org.apache.wicket.feedback.IFeedback;
import org.apache.wicket.feedback.IFeedbackMessageFilter;
import org.apache.wicket.markup.IMarkupFragment;
import org.apache.wicket.markup.html.WebPage;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.form.ValidationErrorFeedback;
import org.apache.wicket.markup.html.link.BookmarkablePageLink;
import org.apache.wicket.markup.html.list.ListView;
import org.apache.wicket.markup.html.panel.FeedbackPanel;
import org.apache.wicket.model.IModel;
import org.apache.wicket.protocol.http.WebApplication;
import org.apache.wicket.request.mapper.parameter.PageParameters;
import org.apache.wicket.util.lang.Args;
import org.apache.wicket.util.lang.Objects;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


/**
 * A helper class to ease unit testing of Wicket applications without the need for a servlet
 * container. To start a test, either use startPage or startPanel:
 * 
 * 
 * // production page
 * public class MyPage extends WebPage
 * {
 * 	public MyPage()
 * 	{
 * 		add(new Label("myMessage", "Hello!"));
 * 		add(new Link("toYourPage")
 * 		{
 * 			public void onClick()
 * 			{
 * 				setResponsePage(new YourPage("Hi!"));
 * 			}
 * 		});
 * 	}
 * }
 * 
* *
 * // test code
 * private WicketTester tester;
 * 
 * public void setUp()
 * {
 * 	tester = new WicketTester();
 * }
 * 
 * public void testRenderMyPage()
 * {
 * 	// start and render the test page
 * 	tester.startPage(MyPage.class);
 * 	// assert rendered page class
 * 	tester.assertRenderedPage(MyPage.class);
 * 	// assert rendered label component
 * 	tester.assertLabel("myMessage", "Hello!");
 * }
 * 
* * The above example is straight forward: start MyPage.class and assert * Label it rendered. Next, we try to navigate through a Link: * *
 * // production page
 * public class YourPage extends WebPage
 * {
 * 	public YourPage(String message)
 * 	{
 * 		add(new Label("yourMessage", message));
 * 		info("Wicket Rocks ;-)");
 * 	}
 * }
 * 
 * // test code
 * public void testLinkToYourPage()
 * {
 * 	tester.startPage(MyPage.class);
 * 	// click link and render
 * 	tester.clickLink("toYourPage");
 * 	tester.assertRenderedPage(YourPage.class);
 * 	tester.assertLabel("yourMessage", "Hi!");
 * }
 * 
* * tester.clickLink(path); will simulate user click on the component (in this case, * it's a Link) and render the response page YourPage. Ok, unit test of * MyPage is completed. Now we test YourPage standalone: * *
 * // test code
 * public void testRenderYourPage()
 * {
 * 	// provide page instance source for WicketTester
 * 	tester.startPage(new YourPage("mock message"));
 * 	tester.assertRenderedPage(YourPage.class);
 * 	tester.assertLabel("yourMessage", "mock message");
 * 	// assert feedback messages in INFO Level
 * 	tester.assertInfoMessages(new String[] { "Wicket Rocks ;-)" });
 * }
 * 
* * Many methods require a 'path' parameter. E.g. the page relative path can be obtained via * {@link Component#getPageRelativePath()}. Since each Component has an ID/name, any Component can * also be referenced by its ID {@link MarkupContainer#get(String)}. And since MarkupContainer's and * its subclasses are containers which allow to add Components (in sync with the markup hierarchy), * you may not only access direct childs but also subchilds like get("myPanel:myForm:myNameField") * separating each ID with a ':'. * * Cookie handling: * * There are some expectations about wicket tester cookie handling which should match as best as * it can be with a real client server request response cycle: * - all valid cookies set before a request is made (tester.getRequest().addCookie()) should * appear in the page request * - all cookies set in the response should appear in the last response (tester.getLastResponse()) * after the request is made (expired cookies and others) * - all cookies set in the response should appear even after a redirect response is made * until the final response (tester.getLastResponse()) is written to the client (wicket tester) * - all valid cookies (maxAge!=0) from the last response should be added to * the next request cookies (tester.getRequest().getCookies()) * * * TODO General: Example usage of FormTester * * @author Ingram Chen * @author Juergen Donnerstag * @author Frank Bille * @since 1.2.6 */ public class WicketTester extends BaseWicketTester { /** log. */ private static final Logger log = LoggerFactory.getLogger(WicketTester.class); /** * Creates a WicketTester and automatically creates a WebApplication, * but the tester will have no home page. */ public WicketTester() { } /** * Creates a WicketTester and automatically creates a WebApplication. * * @param homePage * a home page Class */ public WicketTester(final Class homePage) { super(homePage); } /** * Creates a WicketTester. * * @param application * a WicketTester WebApplication object */ public WicketTester(final WebApplication application) { super(application); } /** * Creates a WicketTester to help unit testing. * * @param application * a WicketTester WebApplication object * @param path * the absolute path on disk to the web application's contents (e.g. war root) - may * be null * * @see org.apache.wicket.mock.MockApplication#MockApplication() */ public WicketTester(final WebApplication application, final String path) { super(application, path); } /** * Creates a WicketTester to help unit testing. * * @param application * a WicketTester WebApplication object * @param servletCtx * the servlet context used as backend */ public WicketTester(WebApplication application, ServletContext servletCtx) { super(application, servletCtx); } /** * Creates a WicketTester to help unit testing. * * @param application * a WicketTester WebApplication object * @param init * force the application to be initialized (default = true) */ public WicketTester(WebApplication application, boolean init) { super(application, init); } /** * Creates a WicketTester to help unit testing. * * @param application * a WicketTester WebApplication object * @param servletCtx * the servlet context used as backend * @param init * force the application to be initialized (default = true) */ public WicketTester(WebApplication application, ServletContext servletCtx, boolean init) { super(application, servletCtx, init); } /** * Asserts that the Ajax location header is present. */ public void assertAjaxLocation() { if (null != getLastResponse().getHeader("Location")) { fail("Location header should *not* be present when using Ajax"); } String ajaxLocation = getLastResponse().getHeader("Ajax-Location"); if (null == ajaxLocation) { throw new AssertionFailedError("Ajax-Location header should be present when using Ajax"); } int statusCode = getLastResponse().getStatus(); if (statusCode != 200) { throw new AssertionFailedError("Expected HTTP status code to be 200 (OK)"); } } /** * Asserts a Component class. * * @param path * path to Component * @param expectedComponentClass * expected Component class */ public void assertComponent(String path, Class expectedComponentClass) { assertResult(isComponent(path, expectedComponentClass)); } /** * Tests that a Component has been added to a AjaxRequestTarget, using * {@link org.apache.wicket.ajax.AjaxRequestTarget#add(Component...)}. This method actually tests that a * Component is on the Ajax response sent back to the client. *

* PLEASE NOTE! This method doesn't actually insert the Component in the client DOM * tree, using JavaScript. But it shouldn't be needed because you just have to trust that Wicket * Ajax JavaScript works. * * @param component * a Component to be tested */ public void assertComponentOnAjaxResponse(Component component) { Result result = isComponentOnAjaxResponse(component); assertResult(result); } /** * Tests that a Component has been added to a AjaxRequestTarget, using * {@link org.apache.wicket.ajax.AjaxRequestTarget#add(Component...)}. This method actually tests that a * Component is on the Ajax response sent back to the client. *

* PLEASE NOTE! This method doesn't actually insert the Component in the client DOM * tree, using JavaScript. But it shouldn't be needed because you just have to trust that Wicket * Ajax JavaScript works. * * @param componentPath * a Component path to test */ public void assertComponentOnAjaxResponse(String componentPath) { Component component = getComponentFromLastRenderedPage(componentPath, false); assertComponentOnAjaxResponse(component); } /** * Asserts the content of last rendered page contains (matches) a given regex pattern. * * @param pattern * a regex pattern to match */ public void assertContains(String pattern) { assertResult(ifContains(pattern)); } /** * The opposite of {@link #assertContains(String)}. * * @param pattern * pattern */ public void assertContainsNot(String pattern) { assertResult(ifContainsNot(pattern)); } /** * Asserts that a component's markup has loaded with the given variation * * @param component * The component which markup to check * @param expectedVariation * The expected variation of the component's markup */ public void assertMarkupVariation(Component component, String expectedVariation) { Result result = Result.PASS; IMarkupFragment markup = getMarkupFragment(component); String actualVariation = markup.getMarkupResourceStream().getVariation(); if (Objects.equal(expectedVariation, actualVariation) == false) { result = Result.fail(String.format("Wrong variation for component '%s'. Actual: '%s', expected: '%s'", component.getPageRelativePath(), actualVariation, expectedVariation)); } assertResult(result); } /** * Asserts that a component's markup has loaded with the given style. * * @param component * The component which markup to check * @param expectedStyle * The expected style of the component's markup. * For example: green in MyPanel_green.html */ public void assertMarkupStyle(Component component, String expectedStyle) { Result result = Result.PASS; IMarkupFragment markup = getMarkupFragment(component); String actualStyle = markup.getMarkupResourceStream().getStyle(); if (Objects.equal(expectedStyle, actualStyle) == false) { result = Result.fail(String.format("Wrong style for component '%s'. Actual: '%s', expected: '%s'", component.getPageRelativePath(), actualStyle, expectedStyle)); } assertResult(result); } /** * Asserts that a component's markup has loaded with the given locale * * @param component * The component which markup to check * @param expectedLocale * The expected locale of the component's markup */ public void assertMarkupLocale(Component component, Locale expectedLocale) { Result result = Result.PASS; IMarkupFragment markup = getMarkupFragment(component); Locale actualLocale = markup.getMarkupResourceStream().getLocale(); if (Objects.equal(expectedLocale, actualLocale) == false) { result = Result.fail(String.format("Wrong locale for component '%s'. Actual: '%s', expected: '%s'", component.getPageRelativePath(), actualLocale, expectedLocale)); } assertResult(result); } private IMarkupFragment getMarkupFragment(Component component) { IMarkupFragment markup = null; if (component instanceof MarkupContainer) { markup = ((MarkupContainer) component).getAssociatedMarkup(); } if (markup == null) { markup = component.getMarkup(); } if (markup == null) { throw new AssertionFailedError(String.format("Cannot find the markup of component: %s", component.getPageRelativePath())); } return markup; } /** * Asserts error-level feedback messages. * * @param expectedErrorMessages * expected error messages */ public void assertErrorMessages(Serializable... expectedErrorMessages) { assertFeedbackMessages(new ExactLevelFeedbackMessageFilter(FeedbackMessage.ERROR), expectedErrorMessages); } /** * Assert info-level feedback messages. * * @param expectedInfoMessages * expected info messages */ public void assertInfoMessages(Serializable... expectedInfoMessages) { assertFeedbackMessages(new ExactLevelFeedbackMessageFilter(FeedbackMessage.INFO), expectedInfoMessages); } /** * Assert there are feedback messages accepted by the provided filter. * * @param filter * the filter that will decide which messages to check * @param expectedMessages * expected feedback messages */ public void assertFeedbackMessages(IFeedbackMessageFilter filter, Serializable... expectedMessages) { List feedbackMessages = getFeedbackMessages(filter); List actualMessages = getActualFeedbackMessages(feedbackMessages); WicketTesterHelper.assertEquals(Arrays.asList(expectedMessages), actualMessages); } /** * Asserts that there is a feedback message provided by a given component * * @param component * the component that provided the expected feedback message. Optional. * @param key * the resource key for the feedback message. Mandatory. * @param model * the model used for interpolating the feedback message. Optional. * @param filter * the filter that decides in which messages to look in. E.g. with a specific * level, rendered or not, etc. */ public void assertComponentFeedbackMessage(Component component, String key, IModel model, IFeedbackMessageFilter filter) { Args.notNull(key, "key"); String expectedMessage = getApplication().getResourceSettings().getLocalizer().getString(key, component, model); List feedbackMessages = getFeedbackMessages(filter); List actualMessages = getActualFeedbackMessages(feedbackMessages); assertTrue(String.format("Feedback message with key '%s' cannot be found in %s", key, actualMessages), actualMessages.contains(expectedMessage)); } /** * Extracts the actual messages from the passed feedback messages. * Specially handles ValidationErrorFeedback messages by extracting their String message * * @param feedbackMessages * the feedback messages * @return the FeedbackMessages' messages */ private List getActualFeedbackMessages(List feedbackMessages) { List actualMessages = new ArrayList<>(); for (FeedbackMessage feedbackMessage : feedbackMessages) { Serializable message = feedbackMessage.getMessage(); if (message instanceof ValidationErrorFeedback) { actualMessages.add(message.toString()); } else { actualMessages.add(message); } } return actualMessages; } /** * Assert that a particular feedback panel is rendering certain messages. * * NOTE: this casts the component at the specified path to a {@link FeedbackPanel}, so it will * not work with custom {@link IFeedback} implementations unless you are subclassing * {@link FeedbackPanel} * * @param path * path to the feedback panel * @param messages * messages expected to be rendered */ public void assertFeedback(String path, Serializable... messages) { final FeedbackPanel fbp = (FeedbackPanel)getComponentFromLastRenderedPage(path); final IModel> model = fbp.getFeedbackMessagesModel(); final List renderedMessages = model.getObject(); if (renderedMessages == null) { fail(String.format("feedback panel at path [%s] returned null messages", path)); } if (messages.length != renderedMessages.size()) { fail(String.format("you expected '%d' messages for the feedback panel [%s], but there were actually '%d'", messages.length, path, renderedMessages.size())); } for (int i = 0; i < messages.length && i < renderedMessages.size(); i++) { final Serializable expected = messages[i]; boolean found = false; for (FeedbackMessage actual : renderedMessages) { if (Objects.equal(expected, actual.getMessage())) { found = true; break; } } if (!found) { assertResult(Result.fail("Missing expected feedback message: " + expected)); } } } /** * Asserts that a Component is invisible. * * @param path * path to Component */ public void assertInvisible(String path) { assertResult(isInvisible(path)); } /** * Asserts the text of a Label Component. * * @param path * path to Label Component * @param expectedLabelText * expected text of the Label */ public void assertLabel(String path, String expectedLabelText) { Label label = (Label)getComponentFromLastRenderedPage(path); assertEquals(expectedLabelText, label.getDefaultModelObjectAsString()); } /** * Asserts the model value of a component. * * @param path * path to the component on the page * @param expectedValue * expected value of the component's model */ public void assertModelValue(String path, Object expectedValue) { Component component = getComponentFromLastRenderedPage(path); assertEquals(expectedValue, component.getDefaultModelObject()); } /** * Asserts the model of a {@link ListView}. * * @param path * path to a {@link ListView} Component * @param expectedList * expected List in the model of the given {@link ListView} */ @Override public void assertListView(String path, List expectedList) { ListView listView = (ListView)getComponentFromLastRenderedPage(path); WicketTesterHelper.assertEquals(expectedList, listView.getList()); } /** * Asserts no error-level feedback messages. */ public void assertNoErrorMessage() { assertNoFeedbackMessage(FeedbackMessage.ERROR); } /** * Asserts no info-level feedback messages. */ public void assertNoInfoMessage() { assertNoFeedbackMessage(FeedbackMessage.INFO); } /** * Asserts there are no feedback messages with a certain level. * * @param level * the level to check for */ public void assertNoFeedbackMessage(int level) { Result result = hasNoFeedbackMessage(level); assertFalse(result.getMessage(), result.wasFailed()); } /** * Asserts a last-rendered Page class. * * @param expectedRenderedPageClass * expected class of last rendered Page */ public void assertRenderedPage(Class expectedRenderedPageClass) { assertResult(isRenderedPage(expectedRenderedPageClass)); } /** * Asserts last-rendered Page against an expected HTML document. *

* Use -Dwicket.replace.expected.results=true to automatically replace the expected * output file. * * @param clazz * Class used to load the file (relative to clazz package) * @param filename * expected output filename String * @throws Exception */ @Override public void assertResultPage(final Class clazz, final String filename) throws Exception { String document = getLastResponseAsString(); DiffUtil.validatePage(document, clazz, filename, true); } /** * Asserts last-rendered Page against an expected HTML document as a * String * * @param expectedDocument * expected output String * @throws Exception */ public void assertResultPage(final String expectedDocument) throws Exception { // Validate the document String document = getLastResponseAsString(); assertEquals(expectedDocument, document); } /** * Asserts that a Component is visible. * * @param path * path to a Component */ public void assertVisible(String path) { assertResult(isVisible(path)); } /** * assert component is enabled. * * @param path * path to component * */ public void assertEnabled(String path) { assertResult(isEnabled(path)); } /** * assert component is enabled. * * @param path * path to component */ public void assertDisabled(String path) { assertResult(isDisabled(path)); } /** * assert form component is required. * * @param path * path to form component */ public void assertRequired(String path) { assertResult(isRequired(path)); } /** * assert form component is required. * * @param path * path to form component */ public void assertNotRequired(String path) { assertResult(isNotRequired(path)); } /** * * @param result */ private void assertResult(Result result) { if (result.wasFailed()) { throw new AssertionFailedError(result.getMessage()); } } /** * Checks whether a component is visible and/or enabled before usage * * @param component */ public void assertUsability(final Component component) { checkUsability(component, true); } /** * * @param link */ public void clickLink(Component link) { clickLink(link.getPageRelativePath()); } /** * Asserts that that the BookmarkablePageLink identified by "id" points to the page as * expected - including parameters. * * @param id * @param pageClass * @param parameters */ public void assertBookmarkablePageLink(final String id, final Class pageClass, final PageParameters parameters) { BookmarkablePageLink pageLink; try { pageLink = (BookmarkablePageLink)getComponentFromLastRenderedPage(id); } catch (ClassCastException e) { throw new IllegalArgumentException("Component with id:" + id + " is not a BookmarkablePageLink"); } assertEquals("BookmarkablePageLink: " + id + " is pointing to the wrong page", pageClass, pageLink.getPageClass()); assertEquals("One or more of the parameters associated with the BookmarkablePageLink: " + id + " do not match", parameters, pageLink.getPageParameters()); } /** * Use -Dwicket.replace.expected.results=true to automatically replace the expected * output file. * * @param * @param testClass * @param pageClass * @param filename * @throws Exception */ public void executeTest(final Class testClass, final Class pageClass, final String filename) throws Exception { log.info("=== " + pageClass.getName() + " ==="); startPage(pageClass); assertRenderedPage(pageClass); assertResultPage(testClass, filename); } /** * Use -Dwicket.replace.expected.results=true to automatically replace the expected * output file. * * @param testClass * @param page * @param filename * @throws Exception */ public void executeTest(final Class testClass, final Page page, final String filename) throws Exception { log.info("=== " + page.getClass().getName() + " ==="); startPage(page); assertRenderedPage(page.getClass()); assertResultPage(testClass, filename); } /** * Use -Dwicket.replace.expected.results=true to automatically replace the expected * output file. * * @param testClass * @param component * @param filename * @throws Exception */ public void executeTest(final Class testClass, final Component component, final String filename) throws Exception { log.info("=== " + component.getClass().getName() + " ==="); startComponentInPage(component); assertResultPage(testClass, filename); } /** * Use -Dwicket.replace.expected.results=true to automatically replace the expected * output file. * * @param * @param testClass * @param pageClass * @param parameters * @param filename * @throws Exception */ public void executeTest(final Class testClass, final Class pageClass, PageParameters parameters, final String filename) throws Exception { log.info("=== " + pageClass.getName() + " ==="); startPage(pageClass, parameters); assertRenderedPage(pageClass); assertResultPage(testClass, filename); } /** * * @param testClass * @param component * @param filename * @throws Exception */ public void executeListener(final Class testClass, final Component component, final String filename) throws Exception { assertNotNull(component); log.info("=== " + testClass.getName() + " : " + component.getPageRelativePath() + " ==="); executeListener(component); assertResultPage(testClass, filename); } /** * * @param testClass * @param behavior * @param filename * @throws Exception */ public void executeBehavior(final Class testClass, final AbstractAjaxBehavior behavior, final String filename) throws Exception { assertNotNull(behavior); log.info("=== " + testClass.getName() + " : " + behavior.toString() + " ==="); executeBehavior(behavior); assertResultPage(testClass, filename); } /** * Assert that the last request redirected to the given Url. * * @param expectedRedirectUrl * expected */ public void assertRedirectUrl(String expectedRedirectUrl) { String actualRedirectUrl = getLastResponse().getRedirectLocation(); assertEquals(expectedRedirectUrl, actualRedirectUrl); } /** * Returns the current Maven build directory taken from the basedir system property, or * null if not set * * @return path with a trailing slash */ public static String getBasedir() { String basedir = System.getProperty("basedir"); if (basedir != null) { basedir = basedir + "/"; } else { basedir = ""; } return basedir; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy