blob: 7f4f2875c2974a1d04f4f9f9fc2829735f2afa2a [file] [log] [blame]
// Copyright 2009-2013 The Apache Software Foundation
//
// Licensed 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.tapestry5.integration.app1;
import org.apache.tapestry5.corelib.mixins.RenderDisabled;
import org.apache.tapestry5.integration.app1.pages.RenderErrorDemo;
import org.testng.annotations.Test;
public class CoreBehaviorsTests extends App1TestCase
{
@Test
public void access_to_page_name()
{
openBaseURL();
assertText("activePageName", "Index");
clickAndWait("link=Grid Demo");
assertText("activePageName", "GridDemo");
}
/**
* also verifies the use of meta data to set the default strategy.
*/
@Test
public void flash_persistence()
{
openLinks("FlashDemo");
assertTextPresent("[]");
clickAndWait("link=show the message");
assertTextPresent("[You clicked the link!]");
clickAndWait(REFRESH_PAGE);
assertTextPresent("[]");
}
@Test
public void component_parameter_default_from_method() throws Exception
{
openLinks("ParameterDefault");
assertTextPresent("Echo component default: [ParameterDefault:echo]");
}
@Test
public void embedded_components()
{
openLinks("Countdown Page");
assertTextPresent("regexp:\\s+5\\s+4\\s+3\\s+2\\s+1\\s+");
assertTextPresent("Brought to you by the org.apache.tapestry5.integration.app1.components.Count");
}
/**
* Tests the ability to inject a Block, and the ability to use the block to
* control rendering.
*/
@Test
public void block_rendering() throws Exception
{
openLinks("BlockDemo");
assertTextPresent("[]");
select("//select[@id='blockName']", "fred");
waitForPageToLoad(PAGE_LOAD_TIMEOUT);
assertTextPresent("[Block fred.]");
select("//select[@id='blockName']", "barney");
waitForPageToLoad(PAGE_LOAD_TIMEOUT);
assertTextPresent("[Block barney.]");
// TAPESTRY-1583
assertTextPresent("before it is defined: [Block wilma].");
}
@Test
public void environmental()
{
openLinks("Environmental Annotation Usage");
assertSourcePresent("[<strong>A message provided by the RenderableProvider component.</strong>]");
}
@Test
public void exception_report()
{
// mismatched tag.
openLinks("BadTemplate Page");
assertTextPresent("org.apache.tapestry5.ioc.internal.OperationException",
"Failure parsing template classpath:org/apache/tapestry5/integration/app1/pages/BadTemplate.tml",
"The element type \"t:foobar\" must be terminated by the matching end-tag \"</t:foobar>\"",
"classpath:org/apache/tapestry5/integration/app1/pages/BadTemplate.tml, line 6",
"<t:foobar>content from template</foobar>");
}
@Test
public void expansion()
{
openLinks("Expansion Page");
assertTextPresent("[value provided by a template expansion]");
}
@Test
public void maps_in_expansions() throws Exception
{
openLinks("Map Expressions in Expansions Demo");
assertText("emptymap", "{}");
assertText("stringmap", "{A:1}");
assertText("numberkeysmap", "{1:one}");
}
@Test
public void expressions_in_js_functions() throws Exception
{
openLinks("Expressions in JS Functions Demo");
click("button1");
waitForCondition("selenium.getValue('target') == 'test1'", PAGE_LOAD_TIMEOUT);
click("button2");
waitForCondition("selenium.getValue('target') == '{key=test2}'", PAGE_LOAD_TIMEOUT);
}
/**
* {@link org.apache.tapestry5.internal.transform.InjectContainerWorker} is
* largely tested by the forms tests
* ({@link RenderDisabled} is built on it). test is for the failure case,
* where a mixin class is used with the wrong
* type of component.
*/
@Test
public void inject_container_failure() throws Exception
{
openLinks("InjectContainerMismatch");
// And exception message:
assertTextPresent("Component InjectContainerMismatch (type org.apache.tapestry5.integration.app1.pages.InjectContainerMismatch) is not assignable to field org.apache.tapestry5.corelib.mixins.RenderDisabled.field (of type org.apache.tapestry5.Field).");
}
@Test
public void inject_component_failure() throws Exception
{
openLinks("InjectComponentMismatch");
assertTextPresent("Unable to inject component 'form' into field form of org.apache.tapestry5.integration.app1.pages.InjectComponentMismatch. Class org.apache.tapestry5.corelib.components.BeanEditForm is not assignable to a field of type org.apache.tapestry5.corelib.components.Form.");
}
@Test
public void injection() throws Exception
{
openLinks("Inject Demo");
// is a test for a named @Inject:
assertTextPresent("<Proxy for Request(org.apache.tapestry5.services.Request)>");
// is a test for an anonymous @Inject and
// ComponentResourcesInjectionProvider
assertTextPresent("ComponentResources[InjectDemo]");
// Another test, DefaultInjectionProvider
assertTextPresent("<Proxy for BindingSource(org.apache.tapestry5.services.BindingSource)>");
// Prove that injection using a marker annotation (to match against a
// marked service) works.
assertTextPresent("Injection via Marker: Bonjour!");
assertText("viaInjectService", "1722 tracks in music library");
}
@Test
public void atinjection() throws Exception
{
openLinks("@javax.inject.Inject Demo");
// is a test for a named @Inject:
assertTextPresent("<Proxy for Request(org.apache.tapestry5.services.Request)>");
// is a test for an anonymous @Inject and
// ComponentResourcesInjectionProvider
assertTextPresent("ComponentResources[AtInjectDemo]");
// Another test, DefaultInjectionProvider
assertTextPresent("<Proxy for BindingSource(org.apache.tapestry5.services.BindingSource)>");
assertTextPresent("Injected Symbol: Symbol contributed to ApplicationDefaults");
// Prove that injection using a marker annotation (to match against a
// marked service) works.
assertTextPresent("Injection via Marker: Bonjour!");
assertTextPresent("Injection via @Named: 1722 tracks in music library");
}
@Test
public void instance_mixin()
{
openLinks("InstanceMixin");
final String[] dates =
{"Jun 13, 1999", "Jul 15, 2001", "Dec 4, 2005"};
for (String date : dates)
{
String snippet = String.format("[%s]", date);
assertSourcePresent(snippet);
}
clickAndWait("link=Toggle emphasis");
for (String date : dates)
{
String snippet = String.format("[<em>%s</em>]", date);
assertSourcePresent(snippet);
}
}
@Test
public void localization()
{
openLinks("Localization");
assertTextPresent("Via injected Messages property: [Accessed via injected Messages]");
assertTextPresent("Via message: binding prefix: [Accessed via message: binding prefix]");
assertTextPresent("From Application Message Catalog: [Application Catalog Working]");
assertTextPresent("Page locale: [en]");
clickAndWait("link=French");
assertTextPresent("Page locale: [fr]");
clickAndWait("link=English");
assertTextPresent("Page locale: [en]");
}
@Test
public void page_injection() throws Exception
{
openLinks("Inject Demo");
clickAndWait("link=Fred");
assertTextPresent("You clicked Fred.");
clickAndWait("link=Back");
clickAndWait("link=Barney");
assertTextPresent("You clicked Barney.");
clickAndWait("link=Back");
clickAndWait("link=Wilma");
assertTextPresent("You clicked Wilma.");
}
@Test
public void passivate_activate() throws Exception
{
openLinks("NumberSelect");
clickAndWait("link=5");
assertTextPresent("You chose 5.");
}
@Test
public void render_phase_method_returns_a_component() throws Exception
{
openLinks("RenderComponentDemo");
assertText("//span[@id='container']", "[]");
// Sneak in a little test for If and parameter else:
assertTextPresent("Should be blank:");
clickAndWait("enabled");
// After clicking the link (which submits the form), the page re-renders
// and shows us
// the optional component from inside the NeverRender, resurrected to
// render on the page
// after all.
assertText("//span[@id='container']/span", "Optional Text");
assertTextPresent("Should now show up:");
}
@Test
public void render_phase_order()
{
openLinks("RenderPhaseOrder");
assertTextPresent("[BEGIN-TRACER-MIXIN BEGIN-ABSTRACT-TRACER BEGIN-TRACER BODY AFTER-TRACER AFTER-ABSTRACT-TRACER AFTER-TRACER-MIXIN]");
}
@Test
public void simple_component_event()
{
final String YOU_CHOSE = "You chose: ";
openLinks("Action Page");
assertFalse(isTextPresent(YOU_CHOSE));
for (int i = 2; i < 5; i++)
{
clickAndWait("link=" + i);
assertTextPresent(YOU_CHOSE + i);
}
}
@Test
public void subclass_inherits_parent_template()
{
openLinks("ExpansionSubclass");
assertTextPresent("[value provided, in the subclass, via a template expansion]");
}
@Test
public void template_overridden()
{
openLinks("Template Overridden by Class Page");
assertTextPresent("Output: ClassValue");
}
@Test
public void pageloaded_lifecycle_method_invoked()
{
openLinks("PageLoaded Demo");
assertTextPresent("[pageLoaded() was invoked.]");
}
@Test
public void navigation_response_from_page_activate() throws Exception
{
openLinks("Protected Page");
assertText("pagetitle", "Security Alert");
// The message is set by Protected, but is rendered by SecurityAlert.
assertTextPresent("Access to Protected page is denied");
}
@Test
public void mixed_page_activation_context_and_component_context()
{
openLinks("Kicker");
clickAndWait("link=kick target");
assertTextSeries("//div[@id='results']//li[%d]", 1, "betty", "wilma", "betty/wilma", "\u82B1\u5B50");
assertTextPresent("No component context.");
clickAndWait("link=go");
assertTextSeries("//div[@id='results']//li[%d]", 1, "betty", "wilma", "betty/wilma", "\u82B1\u5B50");
assertTextSeries("//div[@id='results']//ul[2]/li[%d]", 1, "fred", "barney", "clark kent", "fred/barney", "\u592A\u90CE");
}
@Test
public void page_link_with_explicit_empty_context()
{
openLinks("Kicker");
clickAndWait("link=kick target");
assertTextSeries("//div[@id='results']//li[%d]", 1, "betty", "wilma", "betty/wilma", "\u82B1\u5B50");
clickAndWait("link=Target base, no context");
assertTextPresent("No activation context.");
}
@Test
public void page_link_with_explicit_activation_context()
{
openLinks("PageLink Context Demo", "no context");
assertTextPresent("No activation context.");
clickAndWait("link=PageLink Context Demo");
clickAndWait("link=literal context");
assertText("//div[@id='results']//li[1]", "literal context");
clickAndWait("link=PageLink Context Demo");
clickAndWait("link=computed context");
assertTextSeries("//div[@id='results']//li[%d]", 1, "fred", "7", "true");
clickAndWait("link=PageLink Context Demo");
clickAndWait("link=unsafe characters");
assertText("//div[@id='results']//li[1]", "unsafe characters: !\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~");
clickAndWait("link=PageLink Context Demo");
clickAndWait("link=japanese kanji");
assertText("//div[@id='results']//li[1]", "japanese kanji: \u65E5\u672C\u8A9E");
// TAPESTRY-2221
clickAndWait("link=PageLink Context Demo");
clickAndWait("link=Null in context");
assertText("//div[@id='results']//li[1]", "NULL");
}
private void openLinkParameterTest()
{
openLinks("Link Query Parameters Demo");
assertText("parametercheck", "No Parameters");
}
//TAP5-1496
@Test
public void links_with_unspecified_query_parameter_map()
{
openLinkParameterTest();
clickAndWait("link=Page Link With No Parameters");
assertText("parametercheck", "No Parameters");
clickAndWait("link=Action Link With No Parameters");
assertText("parametercheck", "No Parameters");
clickAndWait("link=Event Link With No Parameters");
assertText("parametercheck", "No Parameters");
}
//TAP5-1496
@Test
public void links_with_explicit_empty_query_parameter_map()
{
openLinkParameterTest();
clickAndWait("link=Page Link With Explicitly Empty Parameters");
assertText("parametercheck", "No Parameters");
clickAndWait("link=Action Link With Explicitly Empty Parameters");
assertText("parametercheck", "No Parameters");
clickAndWait("link=Event Link With Explicitly Empty Parameters");
assertText("parametercheck", "No Parameters");
}
//TAP5-1496
@Test
public void links_with_nonempty_query_parameter_map()
{
openLinkParameterTest();
clickAndWait("link=Page Link With Parameters");
assertText("css=li.param1", "param1: value1");
assertText("css=li.param2", "param2: 10");
//re-open between checks to make sure there is no "bleedover" between checks.
openLinkParameterTest();
clickAndWait("link=Action Link With Parameters");
assertText("css=li.param1", "param1: value1");
assertText("css=li.param2", "param2: 10");
openLinkParameterTest();
;
clickAndWait("link=Event Link With Parameters");
assertText("css=li.param1", "param1: value1");
assertText("css=li.param2", "param2: 10");
}
//TAP5-1495
@Test
public void map_expression_support()
{
openLinkParameterTest();
//more extensive testing done in PropertyConduitSourceImplTest, including multiple key and value types,
//access from methods and nested methods, and map as method arguments.
//This just provides an integration sanity check.
clickAndWait("link=Two Element Map");
assertText("css=li.parama", "parama: valuea");
assertText("css=li.paramb", "paramb: valueb");
}
@Test
public void recursive_components_are_identified_as_errors()
{
openLinks("Recursive Demo");
assertTextPresent(
EXCEPTION_PROCESSING_REQUEST,
"The template for component org.apache.tapestry5.integration.app1.components.Recursive is recursive (contains another direct or indirect reference to component org.apache.tapestry5.integration.app1.components.Recursive). This is not supported (components may not contain themselves).",
"component is <t:recursive>recursive</t:recursive>, so we\'ll see a failure.");
}
@Test
public void render_phase_method_may_return_renderable()
{
openLinks("Renderable Demo");
assertTextPresent("Renderable Demo", "[This proves it works.]");
}
@Test
public void verify_event_handler_invocation_order_and_circumstance()
{
String clear = "link=clear";
openLinks("EventHandler Demo");
clickAndWait(clear);
clickAndWait("link=No Context");
assertText("methodNames",
"[parent.eventHandlerZero(), parent.onAction(), child.eventHandlerZeroChild(), child.onAction()]");
clickAndWait(clear);
clickAndWait("link=Single context value");
assertText(
"methodNames",
"[parent.eventHandlerOne(String), parent.eventHandlerZero(), parent.onAction(String), parent.onAction(), child.eventHandlerOneChild(), child.eventHandlerZeroChild(), child.onAction(String), child.onAction()]");
clickAndWait(clear);
clickAndWait("link=Two value context");
assertText(
"methodNames",
"[parent.eventHandlerOne(String), parent.eventHandlerZero(), parent.onAction(String), parent.onAction(), child.eventHandlerOneChild(), child.eventHandlerZeroChild(), child.onAction(String), child.onAction()]");
clickAndWait(clear);
clickAndWait("link=Two value context (from fred)");
assertText(
"methodNames",
"[parent.eventHandlerOne(String), parent.eventHandlerZero(), parent.onAction(String), parent.onAction(), child.eventHandlerForFred(), child.eventHandlerOneChild(), child.eventHandlerZeroChild(), child.onAction(String), child.onAction(), child.onActionFromFred(String), child.onActionFromFred()]");
}
@Test
public void inherited_bindings()
{
openLinks("Inherited Bindings Demo");
assertTextPresent("Bound: [ value: the-bound-value, bound: true ]", "Unbound: [ value: null, bound: false ]");
}
@Test
public void client_persistence()
{
openLinks("Client Persistence Demo");
// can't assume session won't exist because other tests use form
// components w/ defaults, which means
// session creation to store the ValidationTracker. So we explicitly
// clear the session here.
clickAndWait("link=nix session");
assertTextPresent("Persisted value: []", "Session: [false]");
clickAndWait("link=store string");
assertTextPresent("Persisted value: [A String]", "Session: [false]");
}
@Test
public void attribute_expansions()
{
openLinks("Attribute Expansions Demo");
assertAttribute("//div[@id='mixed-expansion']/@style", "color: blue;");
assertAttribute("//div[@id='single']/@class", "red");
assertAttribute("//div[@id='consecutive']/@class", "goober-red");
assertAttribute("//div[@id='trailer']/@class", "goober-green");
assertText("//div[@id='formal']", "ALERT-expansions work inside formal component parameters as well");
// An unrelated test, but fills in a bunch of minor gaps.
assertSourcePresent("<!-- A comment! -->");
}
@Test
public void event_handler_return_types()
{
openBaseURL();
assertTextPresent(TEST_APP_BANNER);
clickAndWait("link=Return Types");
assertTextPresent("Return Type Tests");
clickAndWait("link=null");
assertTextPresent("Return Type Tests");
clickAndWait("link=string");
assertTextPresent(TEST_APP_BANNER);
goBack();
waitForPageToLoad();
clickAndWait("link=class");
assertTextPresent(TEST_APP_BANNER);
goBack();
waitForPageToLoad();
clickAndWait("link=page");
assertTextPresent(TEST_APP_BANNER);
goBack();
waitForPageToLoad();
clickAndWait("link=link");
assertTextPresent(TEST_APP_BANNER);
goBack();
waitForPageToLoad();
clickAndWait("link=stream");
assertTextPresent("Success!");
goBack();
waitForPageToLoad();
clickAndWait("link=stream page content");
assertTextPresent(TEST_APP_BANNER);
goBack();
waitForPageToLoad();
clickAndWait("link=stream page content with context");
assertTextPresent("music/Details", "Track Details");
assertTextPresent("Bug Juice", "Late Lounge", "Electronica");
goBack();
waitForPageToLoad();
/*
* clickAndWait("link=URL");
* assertTextPresent("Google>");
* goBack();
* waitForPageToLoad();
*/
clickAndWait("link=bad");
assertTextPresent(
EXCEPTION_PROCESSING_REQUEST,
"Handling result from method org.apache.tapestry5.integration.app1.pages.ReturnTypes.onActionFromBadReturnValue().",
"A component event handler method returned the value 20. Return type java.lang.Integer can not be handled.",
"context:ReturnTypes.tml, line 50");
goBack();
waitForPageToLoad();
clickAndWait("link=http error");
assertTextPresent("HTTP ERROR 410", "Oups! Resource disappeared!");
}
@Test
public void missing_template_for_page()
{
openLinks("Missing Template Demo");
assertTextPresent("Page MissingTemplate did not generate any markup when rendered. This could be because its template file could not be located, or because a render phase method in the page prevented rendering.");
}
/**
* This basically checks that the services status page does not error.
*/
@Test
public void services_status()
{
open(getBaseURL() + "t5dashboard/services");
assertTextPresent("services defined in the IoC Registry");
}
/**
* Tests TAPESTRY-1934.
*/
@Test
public void base_class_must_be_in_controlled_package() throws Exception
{
open(getBaseURL() + "invalidsuperclass", "true");
assertTextPresent("Base class org.apache.tapestry5.integration.app1.WrongPackageForBaseClass (super class of org.apache.tapestry5.integration.app1.pages.InvalidSuperClass) is not in a controlled package and is therefore not valid. You should try moving the class to package org.apache.tapestry5.integration.app1.base.");
}
/**
* Tests TAPESTRY-2005.
*/
@Test
public void components_passed_as_parameters() throws Exception
{
openLinks("ComponentParameter Demo");
// This component is inside a block, and is only rendered because it is
// passed as a parameter, of type ActionLink,
// to an ActionLinkIndirect component.
clickAndWait("link=click me");
assertTextPresent("Link was clicked.");
}
/**
* Tests TAPESTRY-1546
*/
@Test
public void inherit_informals() throws Exception
{
openLinks("Inherit Informal Parameters Demo");
assertAttribute("//span[@id='target']/@class", "inherit");
}
/**
* TAPESTRY-1830
*/
@Test
public void var_binding()
{
openLinks("Var Binding Demo");
assertTextSeries("//div[@id='results']//li[%d]", 1, "1", "2", "3");
}
/**
* TAPESTRY-1724
*/
@Test
public void component_event_errors()
{
openLinks("Exception Event Demo", "enable", "force invalid activation context");
assertTextPresent("Exception: Exception in method org.apache.tapestry5.integration.app1.pages.ExceptionEventDemo.onActivate(float)");
clickAndWait("link=force invalid event context");
assertTextPresent("Exception: Exception in method org.apache.tapestry5.integration.app1.pages.ExceptionEventDemo.onActionFromFail(float)");
// Revert to normal handling: return null from the onException() event
// handler method.
clickAndWait("link=disable");
clickAndWait("link=force invalid event context");
assertTextPresent(EXCEPTION_PROCESSING_REQUEST,
"org.apache.tapestry5.runtime.ComponentEventException", "java.lang.NumberFormatException");
}
/**
* TAPESTRY-1518
*/
@Test
public void generic_page_type()
{
openLinks("Generic Page Class Demo");
assertTextPresent("Editor for org.apache.tapestry5.integration.app1.data.Track");
assertText("//label[@for='title']", "Title");
}
/**
* TAPESTRY-2097
*/
@Test
public void render_queue_exception()
{
openLinks("Render Error Demo");
assertTextPresent(EXCEPTION_PROCESSING_REQUEST);
// Just sample a smattering of the vast amount of data in the exception
// report.
assertTextPresent("RenderErrorDemo", "class " + RenderErrorDemo.class.getName(), "RenderErrorDemo:border",
"RenderErrorDemo:echo");
}
/**
* TAPESTRY-2088
*/
@Test
public void primitive_array_as_parameter_type()
{
openLinks("Primitive Array Parameter Demo");
assertSourcePresent("<ul><li>1</li><li>3</li><li>5</li><li>7</li><li>9</li></ul>");
}
/**
* TAPESTRY-1594
*/
@Test
public void ignored_paths_filter()
{
openLinks("Unreachable Page");
// This message changes from one release of Jetty to the next sometimes
assertText("//title", "Error 404 Not Found");
}
/**
* TAPESTRY-2085
*/
@Test
public void render_phase_methods_may_throw_checked_exceptions()
{
openLinks("Render Phase Method Exception Demo");
// Part of TAP5-1508 changed how the exceptiopn gets reported.
assertTextPresent("Render queue error in BeginRender[RenderPhaseMethodExceptionDemo]: Simulated JDBC exception while rendering.",
"java.sql.SQLException");
}
/**
* TAPESTRY-2114
*/
@Test
public void boolean_properties_can_use_get_or_is_as_method_name_prefix()
{
openLinks("Boolean Property Demo", "clear");
assertText("usingGet", "false");
assertText("usingIs", "false");
clickAndWait("link=set");
assertText("usingGet", "true");
assertText("usingIs", "true");
}
/**
* TAPESTRY-1475
*/
@Test
public void discard_persistent_field_changes()
{
openLinks("Persistent Demo");
assertText("message", "");
clickAndWait("link=Update the message field");
assertText("message", "updated");
clickAndWait(REFRESH_PAGE);
assertText("message", "updated");
clickAndWait("link=Discard persistent field changes");
assertText("message", "");
}
/**
* TAPESTRY-2150. Also demonstrates how to add a ValueEncoder for an entity
* object, to allow seamless encoding of
* the entity's id into the URL.
*/
@Test
public void nested_page_names()
{
openLinks("Music Page", "2");
assertText("activePageName", "Music");
clickAndWait("link=The Gift");
assertText("activePageName", "music/Details");
}
/**
* TAPESTRY-2235
*/
@Test
public void generated_activation_context_handlers()
{
openLinks("Music Page", "69");
assertText("activePageName", "Music");
clickAndWait("link=Wake Me Up (Copy)");
assertText("activePageName", "music/Details2");
assertText("//dd[@class='title']", "Wake Me Up");
assertText("//dd[@class='artist']", "Norah Jones");
}
/**
* TAPESTRY-1999
*/
@Test
public void list_as_event_context()
{
openLinks("List Event Context Demo");
assertTextSeries("//ul[@id='eventcontext']/li[%d]", 1, "1", "2", "3");
}
/**
* TAPESTRY-2196
*/
@Test
public void public_field_in_page_class()
{
openLinks("Protected Fields Demo", "Trigger the Exception");
assertTextPresent(
EXCEPTION_PROCESSING_REQUEST,
"Field _field of class org.apache.tapestry5.integration.app1.pages.ProtectedFields must be instrumented, and may not be public.");
}
/**
* TAPESTRY-2078
* <p/>
* Update 4/29/11: Not sure this is necessary as exceptions seem to be reported properly without the old heroics.
*/
@Test
public void noclassdeffound_exception_is_linked_to_underlying_cause()
{
openLinks("Class Transformation Exception Demo");
assertTextPresent("Field _value of class org.apache.tapestry5.integration.app1.pages.Datum must be instrumented, and may not be public.");
}
@Test
public void method_advice()
{
openLinks("Method Advice Demo");
// @ReverseStrings intercepted and reversed the result:
assertText("message", "!olleH");
// @ReverseStrings doesn't do anything for non-Strings
assertText("version", "5");
// @ReverseStrings filtered the checked exception to a string result
assertText("cranky",
"Invocation of method getCranky() failed with org.apache.tapestry5.integration.app1.services.DearGodWhyMeException.");
// Now to check advice on a setter that manipulates parameters
type("text", "Tapestry");
clickAndWait(SUBMIT);
assertText("output-text", "yrtsepaT");
}
@Test
public void component_classes_may_not_be_directly_instantiated()
{
openLinks("Instantiate Page");
assertTextPresent("Class org.apache.tapestry5.integration.app1.pages.Music has been transformed and may not be directly instantiated.");
}
/**
* TAPESTRY-2567
*/
@Test
public void field_annotation_conflict()
{
openLinks("Field Annotation Conflict");
assertTextPresent("Field flashDemo of class org.apache.tapestry5.integration.app1.pages.FieldAnnotationConflict can not be claimed by @org.apache.tapestry5.annotations.Parameter as it is already claimed by @org.apache.tapestry5.annotations.InjectPage.");
}
/**
* TAPESTRY-2610
*/
@Test
public void access_to_informal_parameters()
{
openLinks("Informal Parameters Demo");
assertTextSeries("//dl[@id='informals']/dt[%d]", 1, "barney", "fred", "pageName");
assertTextSeries("//dl[@id='informals']/dd[%d]", 1, "rubble", "flintstone", "InformalParametersDemo");
}
/**
* TAPESTRY-2517
*/
@Test
public void cached_exception_for_loading_failed_page()
{
openLinks("Failed Field Injection Demo");
assertTextPresent("Error obtaining injected value for field org.apache.tapestry5.integration.app1.pages.FailedInjectDemo.buffer: No service implements the interface java.lang.StringBuffer.");
refresh();
waitForPageToLoad(PAGE_LOAD_TIMEOUT);
// Before this bug was fixed, this message would not appear; instead on
// complaining about _$resources would appear which was very confusing.
assertTextPresent("Error obtaining injected value for field org.apache.tapestry5.integration.app1.pages.FailedInjectDemo.buffer: No service implements the interface java.lang.StringBuffer.");
}
/**
* TAPESTRTY-2644
*/
@Test
public void create_page_link_via_page_class()
{
openLinks("PageLink via Class Demo");
assertTextPresent("Demonstrates the use of the @Inject annotation.");
}
/**
* TAP5-256
*/
@Test
public void exception_when_attaching_page()
{
openLinks("Page Attach Failure");
assertTextPresent("Failure inside pageAttached().");
}
/**
* TAP5-284
*/
@Test
public void default_method_for_parameter_returns_primitive()
{
openLinks("Primitive Default Demo");
assertText("value", "99");
}
/**
* TAP5-285
*/
@Test
public void unhandled_client_events_throw_exceptions()
{
openLinks("Unhandled Event Demo", "traditional");
assertTextPresent("Request event 'action' (on component UnhandledEventDemo:traditional) was not handled; you must provide a matching event handler method in the component or in one of its containers.");
openLinks("Unhandled Event Demo");
click("link=ajax");
// Since 5.4 no longer creates the floating console if a native console exists, its now hard to ensure what was written to the console.
}
/**
* TAP5-105
*/
@Test
public void component_in_class_but_not_template_is_an_exception()
{
openLinks("Components Not In Template Demo");
assertTextPresent("Embedded component(s) form are defined within component class org.apache.tapestry5.integration.app1.pages.ComponentsNotInTemplateDemo");
}
/**
* TAP5-309
*/
@Test
public void conflict_between_property_annotation_and_existing_method()
{
openLinks("Getter Method Already Exists");
assertTextPresent("Unable to create new accessor method public java.lang.String getName() on class org.apache.tapestry5.integration.app1.pages.GetterMethodAlreadyExists as the method is already implemented.");
}
/**
* TAP5-181
*/
@Test
public void duplicate_ids_highlight_both_locations()
{
openLinks("Duplicate IDs");
assertTextPresent("Component DuplicateIds already contains a child component with id 'index'. Embedded component ids must be unique (excluding case, which is ignored).");
assertTextPresent("Component DuplicateIds declared original child component with id 'index' in DuplicateIds.tml on line 6.");
}
/**
* TAP5-487
*/
@Test
public void published_parameters()
{
openLinks("Publish Parameters Demo");
assertText("p3-where", "PublishParametersDemo:publish1.publish2.publish3");
assertText("p3-number", "6");
assertText("p3-value", "{passed to publish1.value}");
}
/**
* TAP5-487
*/
@Test
public void conflicting_published_parameter_names_within_same_component()
{
openLinks("Duplicate Published Parameter Name");
assertTextPresent("Parameter 'value' of embedded component 'passwordfield' can not be published as a parameter of "
+ "component org.apache.tapestry5.integration.app1.components.BadPublishDuplicate, "
+ "as it has previously been published by embedded component 'textfield'.");
}
@Test
public void embedded_type_conflict()
{
openLinks("Embedded Component Type Conflict");
assertTextPresent("Embedded component 'input' provides a type attribute in the template ('passwordfield') "
+ "as well as in the component class ('textfield'). You should not provide a type attribute in "
+ "the template when defining an embedded component within the component class.");
}
@Test
public void publish_unknown_parameter()
{
openLinks("Publish Unknown Parameter Demo");
assertTextPresent("Parameter 'xyzzyx' of component org.apache.tapestry5.integration.app1.components.BadPublishUnknown "
+ "is improperly published from embedded component 'publish1' (where it does not exist). "
+ "This may be a typo in the publishParameters attribute of the @Component annotation.");
}
@Test
public void unknown_mixin_id()
{
openLinks("Bad Mixin Id Demo");
assertTextPresent("Mixin id for parameter 'unknownmixinid.foo' not found. Attached mixins: DiscardBody, RenderDisabled.");
}
@Test
public void duplicate_mixin()
{
openLinks("Duplicate Mixin Demo");
assertTextPresent("Failure creating embedded component 'value' of "
+ "org.apache.tapestry5.integration.app1.pages.DupeMixinDemo: "
+ "Mixins applied to a component must be unique. Mixin 'DiscardBody' has already been applied.");
}
@Test
public void unsupported_informal_block_parameter()
{
openLinks("Unsupported Parameter Block Demo");
assertTextPresent(
"Exception assembling root component of page UnsupportedParameterBlockDemo:",
"Component UnsupportedParameterBlockDemo:outputraw does not include a formal parameter 'unexpected' (and does not support informal parameters).");
}
/**
* TAP5-74
*/
@Test
public void component_extends_parent_template()
{
openLinks("Template Override Demo");
// From the parent template (could be overridden, but is not).
assertText("title", "Template Override Demo");
// Overriden by <t:replace> in the child component
assertText("pagecontent", "Content from TemplateOverrideDemo.tml");
}
@Test
public void extend_without_base_template()
{
openLinks("Invalid Template Extend Demo");
assertTextPresent("Component org.apache.tapestry5.integration.app1.pages.InvalidTemplateExtend uses an extension template, but does not have a parent component.");
}
/**
* TAP5-578
*/
@Test
public void abstract_component_class()
{
openLinks("Abstract Component Demo");
assertTextPresent("java.lang.RuntimeException",
"Class org.apache.tapestry5.integration.app1.components.AbstractComponent is abstract and can not be instantiated.");
}
@Test
public void multi_level_parameter_inheritance()
{
openLinks("Multi-Level Inherit Demo");
assertText("prop.middle.bottom", "bound value");
assertText("literal.middle.bottom", "some text");
}
@Test
public void bindparameter()
{
openLinks("BindParameter mixin annotation");
// implicit parameter name
assertEchoMixins("testmixin", "mypropertyvalue", 0, -1, -1, 1, true);
assertText("mypropertyoutput", "mypropertyvalue");
// explicit parameter name
assertEchoMixins("testmixin2", "10", -1, 0, -1, 2, true);
assertText("mypropertyoutput2", "10");
// multiple parameter names; first one found wins.
assertEchoMixins("testmixin3", "hello", -1, -1, 0, 3, true);
// multiple mixins
assertEchoMixins("multimixins", "supervalue", 0, 1, 2, 3, true);
assertText("mypropertyoutput4", "supervalue");
// finally, binding to default bindings (which is tricky because of page
// load invocation order)
assertEchoMixins("defaultbinding", "goodbye", 0, -1, -1, 1, false);
assertText("mypropertyoutput5", "goodbye");
// binding to a published parameter
assertText("publishedparameter_before", "publishedvalue-before");
assertText("p3-value", "publishedvaluetemporaryvalue");
assertText("publishedparameter_after", "publishedvalue-after");
assertText("mypropertyoutput6", "publishedvalue");
}
/**
* asserts that the "echo value" mixins are properly functioning (ie
*
* @BindParameter, and mixin ordering).
* each integer value specifies the echo mixin number (echovalue => 1,
* echovalue2 => 2, echovalue3 => 3; 0 is the original value)
* from which the specified echo mixin is expected to "receive" its value.
* So if echo1From is 2, then the "original value"
* printed by echo1 is expected to be the value set by echo2. If a given
* "from" is < 0, checking the corresponding mixin values is disabled.
*/
private void assertEchoMixins(String fieldName, String originalValue, int echo1From, int echo2From, int echo3From,
int fieldFrom, boolean isField)
{
String[] vals =
{originalValue, "temporaryvaluefromechovaluemixin", "3", "world"};
String before = fieldName + "_before";
String after = fieldName + "_after";
if (echo1From > -1)
{
assertText(before, vals[echo1From] + "-before");
assertText(after, vals[echo1From] + "-after");
}
if (echo2From > -1)
{
assertText(before + "2", "echo2-" + vals[echo2From] + "-before");
assertText(after + "2", "echo2-" + vals[echo2From] + "-after");
}
if (echo3From > -1)
{
assertText(before + "3", "echo3-" + vals[echo3From] + "-before");
assertText(after + "3", "echo3-" + vals[echo3From] + "-after");
}
if (isField)
assertFieldValue(fieldName, vals[fieldFrom]);
else
assertText(fieldName, vals[fieldFrom]);
}
@Test
public void missing_componentclass()
{
openLinks("Missing Component Class Exception");
assertTextPresent(
EXCEPTION_PROCESSING_REQUEST,
"Failure creating embedded component 'componentwithnotype' of org.apache.tapestry5.integration.app1.pages.MissingComponentClassException: You must specify the type via t:type, the element, or @Component");
}
@Test
public void session_attribute()
{
openLinks("SessionAttribute Demo");
assertTextPresent("Foo");
assertTextPresent("Bar");
clickAndWait("link=Read SessionAttribute");
assertTextPresent("read Foo");
assertTextPresent("read Bar");
}
/**
* TAPESTRY-1598
*/
@Test
public void value_encoder_via_type_coercer()
{
openLinks("Magic ValueEncoder Demo");
select("number", "25");
clickAndWait(SUBMIT);
String locator = "//span[@id='selectednumber']";
assertText(locator, "25");
select("number", "100");
clickAndWait(SUBMIT);
assertText(locator, "100");
}
/**
* TAPESTRY-2184
*/
@Test
public void create_action_link_while_not_rendering()
{
openLinks("Action via Link Demo", "via explicit Link creation");
assertText("message", "from getActionURL()");
}
/**
* TAPESTRY-2244
*/
@Test
public void cached()
{
openLinks("Cached Annotation");
assertText("value", "000");
assertText("value2size", "111");
assertText("//span[@class='watch'][1]", "0");
assertText("//span[@class='watch'][2]", "0");
assertText("//span[@class='watch'][3]", "1");
clickAndWait(BACK_TO_INDEX);
// TAPESTRY-2338: Make sure the data is cleared.
clickAndWait("link=Cached Annotation");
assertText("value", "000");
assertText("value2size", "111");
assertText("//span[@class='watch'][1]", "0");
assertText("//span[@class='watch'][2]", "0");
assertText("//span[@class='watch'][3]", "1");
}
/**
* TAPESTRY-2244
*/
@Test
public void override_method_with_cached()
{
openLinks("Cached Annotation2");
assertText("value", "111");
clickAndWait(BACK_TO_INDEX);
// TAPESTRY-2338: Make sure the data is cleared.
clickAndWait("link=Cached Annotation2");
assertText("value", "111");
}
/**
* TAPESTRY-2542
*/
@Test
public void has_body()
{
openLinks("Has Body Demo");
assertText("nobody", "false");
assertText("somebody", "true");
}
@Test
public void bindparameter_nomatchingparameter()
{
openLinks("BindParameter error handling");
assertTextPresent(
EXCEPTION_PROCESSING_REQUEST,
"Failure binding parameter field 'boundParameter' of mixin BindParameterNoSuchParameter:throwexception$echovalue2 (type org.apache.tapestry5.integration.app1.mixins.EchoValue2)",
"Containing component org.apache.tapestry5.corelib.components.Any does not contain a formal parameter or a published parameter matching any of boundParameter, value.");
}
@Test
public void bindparameter_on_componentfield_throws_exception()
{
openLinks("BindParameter on component");
assertTextPresent(
EXCEPTION_PROCESSING_REQUEST,
"@BindParameter was used on field 'value' of component class 'org.apache.tapestry5.integration.app1.components.BindParameterComponent', but @BindParameter should only be used in mixins.");
}
@Test
public void trigger_demo()
{
openLinks("Trigger Demo");
assertTextPresent("Event 'provideAdditionalMarkup' handled.");
}
@Test
public void xml_content() throws Exception
{
open(getBaseURL() + "xmlcontent");
// Commented out ... Selenium can't seem to handle an XML response.
// assertSourcePresent("<![CDATA[< & >]]>");
}
@Test
public void secure_page_access()
{
openLinks("Secure Page Demo");
assertText("secure", "secure");
assertText("message", "Triggered from Index");
clickAndWait("link=click");
assertText("secure", "secure");
assertText("message", "Link clicked");
clickAndWait(SUBMIT);
assertText("secure", "secure");
assertText("message", "Form submitted");
clickAndWait(BACK_TO_INDEX);
// Back to the insecure home page.
assertText("activePageName", "Index");
}
/**
* TAP5-815
*/
@Test
public void test_asset_protection()
{
// Have to watch out for minor differences in error messages from one version of Jetty to
// the next.
// context resources should be available by default.
openLinks("Asset Protection Demo");
clickAndWait("link=Available File");
assertTextPresent("This file should be available to clients.");
openLinks("Asset Protection Demo");
clickAndWait("link=Unavailable CSS");
assertTextPresent("HTTP ERROR 404");
openLinks("Asset Protection Demo");
clickAndWait("link=WEB-INF");
assertTextPresent("HTTP ERROR 404");
openLinks("Asset Protection Demo");
clickAndWait("link=WEB-INF/");
assertTextPresent("HTTP ERROR 404");
openLinks("Asset Protection Demo");
clickAndWait("link=Available File2");
assertTextPresent("This file should be available to clients.");
}
/**
* TAP5-964
*/
@Test
public void failure_inside_default_object_renderer()
{
openLinks("RenderObject Exception Demo");
assertText(
"container",
"Exception rendering description for object of type org.apache.tapestry5.integration.app1.data.NullToString: (java.lang.NullPointerException) NPE from NullToString");
}
/**
* TAP5-966
*/
@Test
public void module_loading()
{
openLinks("Test Only Service Demo");
assertText("message", "TestOnly service message");
}
/**
* TAP5-948
*/
@Test
public void page_reset_annotation()
{
openLinks("PageReset Annotation Demo");
assertText("current", "0");
clickAndWait("link=increment");
assertText("current", "1");
clickAndWait("link=increment");
assertText("current", "2");
clickAndWait("link=refresh");
assertText("current", "2");
clickAndWait(BACK_TO_INDEX);
clickAndWait("link=PageReset Annotation Demo");
assertText("current", "0");
}
/**
* TAP5-948
*/
@Test
public void page_reset_annotation_on_bad_method()
{
openLinks("PageReset Annotation Failure");
assertTextPresent(
"Method org.apache.tapestry5.integration.app1.pages.PageResetFailure.reset(java.lang.String)",
"is invalid: methods with the @PageReset annotation must return void, and have no parameters.");
}
/**
* TAP5-1056
*/
@Test
public void injection_of_application_message_catalog_into_service()
{
openLinks("Inject Global Messages into Service Demo");
assertText("status", "Application Catalog Working");
}
/**
* TAP5-1121
*/
@Test
public void discard_after()
{
openLinks("@DiscardAfter Demo");
type("stringValue", "foo bar baz");
clickAndWait("//input[@id='keep']");
assertTextPresent("Value is: 'foo bar baz'");
clickAndWait("//input[@id='discard']");
assertTextPresent("Value is: ''");
// Once again
type("stringValue", "barney quux");
clickAndWait("//input[@id='keep']");
assertTextPresent("Value is: 'barney quux'");
clickAndWait("//input[@id='discardWithCheckedException']");
assertTextPresent("Oops! Error occured");
openLinks("@DiscardAfter Demo");
assertTextPresent("Value is: 'barney quux'");
}
/**
* TAP5-1080
*/
@Test
public void context_lost_on_secure_page_redirect()
{
open("/securepage/mycontext");
assertText("context", "mycontext");
}
/**
* TAP5-424
*/
@Test
public void multiple_resources_contributed_to_global_message_catalog()
{
openLinks("Library Messages Demo");
assertText("id=no-override", "[pre-app]");
assertText("id=override", "[app]");
}
/**
* TAP5-1254
*/
@Test
public void decorate_page_render_link()
{
openLinks("Decorate Page Render Link Demo");
clickAndWait("link=refresh");
assertTextPresent("Page Render Link Decorated: true");
}
/**
* TAP5-1254
*/
@Test
public void decorate_component_event_link()
{
openLinks("Decorate Component Event Link Demo");
clickAndWait("link=refresh");
assertTextPresent("Component Event Link Decorated: true");
}
/**
* TAP5-2070
*/
@Test
public void unknown_activation_context_demo()
{
openLinks("Unknown Activation Context Demo");
assertText("//title", "Error 404 Activation context <EventContext: Unwanted, context>" +
" unrecognized for page class org.apache.tapestry5.integration.app1.pages.UnknownActivationContextDemo");
}
/**
* TAP5-2070
*/
@Test
public void known_activation_context_demo()
{
openLinks("Known Activation Context Demo");
assertTextPresent("Page called with correct activation context",
"You should never see me if use an erroneous activation context");
}
}