6

Background

I'm trying to build the usual "URL hack" to default some field values when a new record is created. This is a simple override that basically has a page like:

<apex:page standardController="Account" extensions="Redirect" action="{!redirect}"></apex:page>

Within the Redirect extension, I basically evaluate a URLFOR formula, create a PageReference, tweak the parameters, then return that value:

 public class Redirect {
     PageReference ref;
     public Redirect(ApexPages.StandardController controller) {
         Map<String, String> params = ApexPages.currentPage().getParameters();
         // Modify "params" here ...
         Component.Apex.outputText text = new Component.Apex.OutputText();
         text.expressions.value = '{!$Action.Account.New, null, null, true)}';
         ref = new PageReference((String)text.value);
         ref.getParameters().putAll(params);
         ref.setRedirect(true);
     }
     public PageReference redirect() {
         return ref;
     }
}

The Problem

This works just fine for the page override, but in a unit test, I get the typical* "Internal Salesforce.com Error" message.

* (Typical in the sense that whenever I try to get clever, I find a gack.)

I created a pared-down version of this code, which I'll include here. Anyone should be able to replicate this simply by copying the code.

Sample

Controller

public class Fail {
    public String result { get; set; }

    public Fail() {
        Component.Apex.OutputText outputText = new Component.Apex.OutputText();
        outputText.expressions.value = '{!URLFOR($Action.Opportunity.new, null, null, true)}';
        result = (String)outputText.value;
    }
}

The Page

<apex:page controller="Fail">
    {!result}
</apex:page>

The Unit Test

@isTest class FailTest {
    @isTest static void test() {
        Test.setCurrentPage(Page.FailPage);
        Fail controller = new Fail();
    }
}

The Debug Logs

The problem happens on line 7. Depending on if you're viewing the page or unit test log, you'll be okay or you'll crash...

Visualforce Page

16:46:25.037 (37809369)|STATEMENT_EXECUTE|[7]
16:46:25.040 (40080177)|HEAP_ALLOCATE|[7]|Bytes:183
16:46:25.040 (40114840)|SYSTEM_METHOD_ENTRY|[7]|Fail.__sfdc_result(String)
16:46:25.040 (40176294)|VARIABLE_ASSIGNMENT|[-1]|this|{}|0x3e9bbfb2
16:46:25.040 (40201749)|VARIABLE_ASSIGNMENT|[-1]|value|"<redacted> (163 more) ..."
16:46:25.040 (40222019)|VARIABLE_ASSIGNMENT|[2]|this.result|"<redacted> (163 more) ..."|0x3e9bbfb2
16:46:25.040 (40231016)|SYSTEM_METHOD_EXIT|[7]|phyrfox.Fail.__sfdc_result(String)

Unit Test

16:45:23.304 (304629894)|STATEMENT_EXECUTE|[7]
16:45:23.311 (311852850)|HEAP_ALLOCATE|[7]|Bytes:74
16:45:23.311 (311919790)|CONSTRUCTOR_EXIT|[4]|01p50000000IXHe|<init>()
16:45:23.311 (311995561)|FATAL_ERROR|System.UnexpectedException: Internal Salesforce Error: 1023487650-296345 (2002653621) (2002653621)

The Question

Does anyone know why this is broken? Is there a quick workaround? Of course, I'm going to contact support as well, but I wanted this out here to see if the community might have experienced this before and how it can be fixed.

  • I don't think this is URLFOR-related - I think that any expression such as outputText.expressions.value = '{!1<>2}'; can't be cast to a string in the outputText.value property in a testmethod – cropredy Jul 22 '15 at 23:40
  • @crop1645 I wouldn't necessarily expect to cast to a string (1<>2 should be a Boolean value), but you're absolutely right. Anything that's not an expression (e.g. expressions.value = 'Hello World') just returns an error about how it's an invalid expression, but using an expression of any type returns a GACK if you try to access the evaluated value. I'm doubly annoyed now. – sfdcfox Jul 22 '15 at 23:55
3

The problem is that unit testing does not currently invoke an entire Visualforce context. I have received a story number (with safe harbor attached) that this will be considered for a future version. Basically, expressions cannot be evaluated within test context, so the solution was to use something like this:

result = Test.isRunningTest()?'test-value':(String)outputText.value;
| improve this answer | |
0

I modified the pared-down controller by adding 'expressions' to the last statement.

    result = (String)outputText.expressions.value;

Worked for me.

| improve this answer | |
  • That returns the original expression. I need the evaluated value. – sfdcfox Jul 22 '15 at 23:08

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.