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.

2
  • 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, 2015 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, 2015 at 23:55

2 Answers 2

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;
0

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

    result = (String)outputText.expressions.value;

Worked for me.

1
  • That returns the original expression. I need the evaluated value.
    – sfdcfox
    Jul 22, 2015 at 23:08

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .