I am new to coding and am using Salesforce.
I need help understanding how to create a test class for a controller extension.
I am clutching at straws when building the Test Class and now have 66% code coverage. Your help to adjust the below code will be much appreciated and help greatly in my understanding.
The Visualforce page is very simple:
<apex:page standardController="Case"
extensions="Case_ListOppSplits_Controller" lightningStylesheets="true">
<apex:pageBlock >
<apex:pageBlockTable value="{!Opportunity_Splits}" var="oppSplit">
<apex:column value="{!oppSplit.Name}"/>
<apex:column value="{!oppSplit.Split_Loan_Amount__c}"/>
<apex:column value="{!oppSplit.Loan_Usage__c}"/>
<apex:column value="{!oppSplit.Loan_Purpose__c}"/>
<apex:column value="{!oppSplit.Rate_Type__c}"/>
<apex:column value="{!oppSplit.Repayment_Type__c}"/>
</apex:pageBlockTable>
</apex:pageBlock>
</apex:page>`
The controller extension is:
public class Case_ListOppSplits_Controller {
public Case myCase;
public Case_ListOppSplits_Controller(ApexPages.StandardController stdController){
this.myCase = (Case)stdController.getRecord();
}
public list<Opportunity_Split__c> getOpportunity_Splits(){
Case currentCase = [SELECT Id, Subject, Opportunity__c FROM Case WHERE Id =: ApexPages.currentPage().getParameters().get('id')];
List<Opportunity_Split__c> OppSplits = [SELECT Id, Name, Opportunity__c, Loan_Purpose__c, Loan_Type__c, Loan_Usage__c, Rate_Type__c, Repayment_Type__c, Split_Loan_Amount__c FROM Opportunity_Split__c WHERE Opportunity__c =: currentCase.Opportunity__c];
return OppSplits;
}
}
Test Class:
#isTest
public class Case_ListOppSplits_Controller_Test {
static testMethod void testMethod1()
{
Case testCase = new Case();
testCase.Subject='Test Case';
testCase.Opportunity__c='0067F00000N8vSVQAZ';
testCase.RecordTypeId='0126D000000qSBcQAM'; //UA
testCase.Status='Assigned';
insert testCase;
Test.StartTest();
PageReference pageRef = new PageReference('https://omniwealth--dwr.my.salesforce.com/apex/Case_OpportunitySplits?id='+testCase.Id);
ApexPages.StandardController sc = new ApexPages.StandardController(testCase);
Case_ListOppSplits_Controller extn = new Case_ListOppSplits_Controller(sc);
List<Opportunity_Split__c> listOppSplits = extn.getOpportunity_Splits();
Test.StopTest();
}
}
It looks like you are trying to utilize existing data (which you shouldn't do) without adding #seeAlldata=true. What you should do is create the opportunities and splits in your test code before you call your controller methods.
On a side note, you have the myCase record in your controller, so your query in getOpportunitySplits can utilize it instead of the page parameter. (Where Id =: myCase.Id).
Once you create the opportunity and splits or set seealldata, you should increase the coverage. If you decided to use seeAllData, know that your test will fail when attempting to deploy to production since the opportunity id values probably won't match.
Related
I'm working on visualforce and apex and I got a situation where I want to combine 3 different tables in which handyman's name is common. Also, the specialities custom field on handyman custom object is a multipicklist so I couldn't query this directly from any of openorders or closeorders aggregated query because we cannot group by specialities i.e. a multipicklist. I would be very glad if someone help me out with this.
Note: orders custom object has lookup field on handyman.
Visualforce Page Code
<apex:page standardController="Orders__c" extensions=“HandymanInfo">
<apex:form>
<apex:pageBlock>
<apex:pageBlockSection columns="6" title=“ Handyman Tables">
<apex:pageBlockTable value=“{!lsthandyman}” var=“h”>
<apex:column value=“{!h.Name}">
<apex:facet name="header”>Handyman Name</apex:facet>
</apex:column>
<apex:column value=“{!h.Specialities__c}" >
<apex:facet name="header">Specialities</apex:facet>
</apex:column>
</apex:pageBlockTable>
<apex:pageblocktable value=“{!openorders}" var="oo">
<apex:column value="{!oo[’n']}"><apex:facet name="header”>Handyman Name</apex:facet></apex:column>
<apex:column value="{!oo[’sumopen']}"><apex:facet name="header”>Total Orders Opened</apex:facet></apex:column>
</apex:pageblocktable>
<apex:pageBlockTable value=“{!closeorders}" var="co">
<apex:column value="{!co[’n']}"><apex:facet name="header”>Handyman Name</apex:facet></apex:column>
<apex:column value="{!co[’sumclosed']}"><apex:facet name="header">Total Orders Closed</apex:facet></apex:column>
</apex:pageBlockTable>
</apex:pageBlockSection>
</apex:pageBlock>
</apex:form>
</apex:page>
Controller Class Code:
public class HandymanInfo {
public List<Handyman__c> lsthandyman {get;set;}
Public List<AggregateResult> openorders {get; set;}
Public List<AggregateResult> close orders {get; set;}
public HandymanInfo(ApexPages.StandardController controller) {
lsthandyman = [SELECT Name,Specialities__c FROM Handyman__c ORDER BY Name ASC];
openorders = [SELECT Handyman__r.Name n, COUNT(Name) sumopen FROM Orders__c
WHERE ((Status__c='New') OR (Status__c ='Assigned’) OR (Status__c='Accepted') OR
(Status__c ='In Progress'))
GROUP BY Handyman__r.Name
ORDER BY Handyman__r.Name ASC];
closeorders = [SELECT Handyman__r.Name n, COUNT(Name) sumclosed FROM Orders__c
WHERE ((Status__c='Completed') OR (Status__c='In Review’) OR (Status__c ='Paid'))
GROUP BY Handyman__r.Name
ORDER BY Handyman__r.Name ASC];
}
}
Are orders -> handyman connected in lookup relationship or master detail? can order be without handyman? if the handyman would ever be deleted - would you expect to cascade delete the orders or would you want to keep the "orphans"?
If you have it as master-detail then you could make 2 rollup fields from order to handyman. And then your controller becomes very simple, SELECT Name, Specialities__c, OrdersCountOpen__c, OrdersCountClosed__c FROM Handyman__c ORDER BY Name, job done.
If it has to stay as lookup... You could make 2 Map<Id, Integer> where key would be the handyman's id and value would be the count. Or even cheat a bit with a subquery to get open orders and then just run another query for closed.
// make this your class variable
public Map<Id, Integer> closedOrders {get; private set;}
// and then
lsthandyman = [SELECT Name, Specialities__c,
(SELECT Id FROM Orders__r WHERE Status__c IN ('New', 'Assigned', 'Accepted', 'In Progress'))
FROM Handyman__c
ORDER BY Name ASC];
closedOrders = new Map<Id, Integer>();
// there's no guarantee all handymen have any closed orders and we don't want to display error if map key isn't found. So let's make sure we have something in there even if it's all zeroes
for(Handyman__c h : lsthandyman){
closedOrders.put(h.Id, 0);
}
// and now let's get some actual closed order numbers
for(AggregateResult ar : [SELECT Handyman__c h, COUNT(Id) cnt
FROM Orders__c
WHERE Status__c IN ('Completed','In Review’,'Paid')
GROUP BY Handyman__c]){
closedOrders.put((Id) ar.get('h'), Integer.valueOf(ar.get('cnt')));
}
And then your Visualforce will be something like
<apex:pageBlockTable value=“{!lsthandyman}” var=“h”>
<apex:column header="Handyman Name" value=“{!h.Name}"/>
<apex:column header="Specialities" value=“{!h.Specialities__c}"/>
<apex:column header="# Open" value="{!h.Orders__r.size}" />
<apex:column header="# Closed" value="{!closedOrders[h.Id]}" />
</apex:pageBlockTable>
I have a senario where i will be dispalying input text fieldon vf page ,when i enter some value and click on search button the realted accounts should be displayed depending on that keyword.
I have tried the following code ,but i am unable to resolve the error Unknown property 'VisualforceArrayList.Name'
The below is my code:
class:
public class AccountswithKeywordfrompage {
public string keyword{get;set;}
public List<List<Account>> accountlist{get;set;}
public void Accounts(){
keyword = System.currentPageReference().getParameters().get('search');
accountlist=[FIND '+keyword' IN ALL FIELDS
RETURNING Account(Name)];
}
}
vf page:
<apex:page controller="AccountswithKeywordfrompage" standardStylesheets="false">
<apex:form>
<apex:inputText label="SearchAccounts" id="search">
<apex:commandButton value="search" action="{!Accounts}"/>
</apex:inputText>
<apex:pageblock>
<apex:pageblockTable value="{!accountlist}" var="accountobj">
<apex:outputlink value="{!accountobj.Name}"/>
</apex:pageblockTable>
</apex:pageblock>
</apex:form>
</apex:page>
Can anyone help me to solve the issue ?
accountlist is a List<List<Account>>, which is the wrong type; a SOSL search returns a List<List<sObject>>. It just so happens that your SOSL search only returns Account results.
When you iterate over a List<List<sObject>>:
<apex:pageblockTable value="{!accountlist}" var="accountobj">
the type of the iteration variable is List<Account>, which has no Name property.
The cleanest solution is to declare your variable as a List<Account> and extract the first element of the returned List<List<sObject>> from SOSL.
Need your inputs in a scenario I am currently stuck in. Here are the details. Appreciate your time and all your inputs.
currently I am able to see the values retrieved in controller but they are not being displayed on visualforce page.
Requirement: I need to email bulk of selected contacts. When there is no email to selected contacts, we are required to populate the name of contacts on UI who do not have the email. I am able to accomplish first part of requirement but stuck on displaying contact names on visual force page .
List button : BulkEmailTest which calls firstVF visual force page.
firstVF code:
<apex:page standardController="Contact" extensions="FirstController" recordSetVar="listRecs"
action="{!send}">
Emails are being sent!
<script> window.history.back();
</script>
</apex:page>
FirstController code: for simplified code, I have edited snippet for contacts with email as our priority is only related to contacts with no email.
public with sharing class FirstController
{
public List<Contact> noEmail {get;set;}
public Contact contact;
public List<Contact> allcontact {get; set;}
Id test;
public Contact getAllContact() {
return contact;
}
ApexPages.StandardSetController setCon;
ApexPages.StandardController setCon1;
public static Boolean err{get;set;}
public FirstController(ApexPages.StandardController controller)
{
setCon1 = controller;
}
public FirstController(ApexPages.StandardSetController controller)
{
setCon = controller;
}
public PageReference cancel()
{
return null;
}
public FirstController()
{
}
public PageReference send()
{
noEmail = new List<Contact>();
set<id> ids = new set<id>();
for(Integer i=0;i<setCon.getSelected().size();i++){
ids.add(setCon.getSelected()[i].id);
}
if(ids.size() == 0){
err = true;
return null;
}
List<Contact> allcontact = [select Email, Name, firstName , LastName from Contact where Id IN :ids];
for(Contact current : allcontact)
{
system.debug(current);
if (current.Email!= null)
{
PageReference pdf = Page.pdfTest;
pdf.getParameters().put('id',(String)current.id);
system.debug('id is :'+current.id);
pdf.setRedirect(true);
return pdf;
}
else //No email
{
system.debug('in else current'+current );
noEmail.add(current);
// noEmail.add(current);
system.debug('in else noemail'+noEmail );
}//e
}
if(noEmail.size()>0 ) {
PageReference pdf1 = Page.NoEmailVF;
pdf1.getParameters().put('Name', String.valueOf(noEmail));
system.debug('pring noEmail' +noEmail);
pdf1.setRedirect(false);
return pdf1;
}
return null;
}
}
NoEmailVF visual force page code
<apex:page controller="FirstController">
<b> Emails are not sent to below contacts :
<table border="1">
<tr>
<th>Name</th>
</tr>
<apex:repeat var="cx" value="{!allcontact}" rendered="true">
<tr>
<td>{!cx.name}</td>
</tr>
</apex:repeat>
</table>
<p> Please note that emails are not sent to selected Donors only when
they did not make any donation for that year or if they do not have email address listed. </p>
<p>If you still wish to retrieve donations made in this year, then you may use "Hard Copy" button listed on the Donor record to have the data printed. </p>
</b>
<apex:form >
<apex:commandButton action="{!cancel}" value="Back" immediate="true"/>.
</apex:form>
</apex:page>
It's bit messy. I think I know why it doesn't work but I'm also going to give you few tips how to clean it up.
I don't think you need 2 separate pages. You could do it on 1 page. I'm not even sure what were you trying to accomplish. Should the user be moved to previous page (some listview button I guess? Wherever history.back() takes them). Or to Page.NoEmailVF. (and there's even Page.pdfTest thrown into the mix ;))
If you're sure you need multiple pages - here's how you can transfer "state" of the controller across pages. It should work automatically as long as they share same controller (or extension), no need to pass anything via url: https://developer.salesforce.com/docs/atlas.en-us.pages.meta/pages/pages_quick_start_wizard.htm
Your constructors don't do much. They save the references to standard(set)controller but they don't run any queries. Contacts aren't queried until the send() method.
You're hoping to pass the noEmail parameter with String.valueOf(List<Contact>). It's... uh.. it probably does something but after redirect you don't read anything. The NoEmailVF page has just <apex:page controller=... (not an extension) so the FirstController() (the one without any parameters) is called. And it has empty body! It completely ignores what was passed via url. It probably could read what you passed using ApexPages.currentPage().getParameters().get('Name') but then honestly no idea what you can do to create real list of contacts out of such string. Messy. You probably could do some JSON.serialize and then deserialize but I don't like the whole idea.
And last but not least - calling page action is evil, unexpected for the user and against salesforce security best practices. Pls check my old answer https://salesforce.stackexchange.com/a/28853/799
So...
What a random internet stranger thinks you need:
1 VF page. With only 1 constructor, the one that takes StandardSetController.
In the constructor inspect the ssc.getSelected() and query SELECT Id, Name FROM Contact WHERE Id IN :ssc.getSelected() AND Email = null. Save the results of the query into public contactsWithoutEmail {get; private set;}
Do NOT have the action={!send} unless you absolutely need it automated. it should be conscious user's decision to click some final "Do it!" button.
In the send() method query only these SELECT Id, Name FROM Contact WHERE Id IN :ssc.getSelected() AND Email != null and process them.
In visualforce - use <apex:pageBlockTable>, <apex:dataTable> or similar to display contactsWithoutEmail. No need to hand-craft the html.
And I recommend making send a normal apex:commandButton, not action
I have two custom objects, X and Y.
The object Y is related to X by lookup YretatedX__c.
I am trying to show all Y related to X y standart page of X whith a visualforce.
Visualforce:
<apex:page standardController="X__c" extensions="related_list">
<apex:detail relatedList="true">
<apex:relatedList list="Y__c" subject="{!AllRelated}"/>
</apex:detail>
</apex:page>
Apex Class:
public class related_list {
private X__c x;
private Id idX;
public List<Y__c> AllRelated = new Y__c[]{};
public related_list(ApexPages.StandardController controller) {
this.x=(X__c)controller.getRecord();
idX = this.x.Id;
}
public List<Y__c> getAllRelated() {
AllRelated = [SELECT id FROM Y__c WHERE YretatedX__c =: this.idX];
return AllRelated;
}
}
In X page, the visualforce only shows:
Invalid parameter value "[a120E0000001234567, a120E0000007654321]" for parameter "id"
This Ids are valid for Y objects retated to this X object
I tried a lot, but I can find a solution.
I think you're not understanding the attributes of the apex:relatedList component in Visualforce.
Refer to this:
https://developer.salesforce.com/docs/atlas.en-us.pages.meta/pages/pages_compref_relatedList.htm
Note that you don't actually need to query for the records to display them with the component.
All you need is this:
<apex:relatedList list="Contacts"/>
You need to specify the Relationship Name for the list attribute
You don't need to specify the subject (the subject is the record who is the Parent of the list you are trying to show) as this would automatically be populated by the Standard Controller
Hope that helps.
I found a solution using <apex:pageBlockTable instead of <apex:relatedList
<apex:page standardController="X__c" extensions="related_list">
<apex:pageblock id="CustomList" title="Y" >
<apex:pageBlockTable value="{!AllRelated}" var="y" rendered="true">
<apex:column value="{!y.id}"/>
</apex:pageBlockTable>
</apex:pageblock>
</apex:page>
I am following this link to Create Save and New Functionality on page
How to implement "Save & New" functionality in a VisualForce Page
According to that i have did following
1.Create a apex class Opportunity and implement extension method
public with sharing class Opportunity
{
ApexPages.standardController m_sc = null;
public Opportunity(ApexPages.standardController sc)
{
m_sc = sc;
}
public Pagereference doSaveAndNew()
{
SObject so = m_sc.getRecord();
upsert so;
string s = '/' + ('' + so.get('Id')).subString(0, 3) + '/e?';
ApexPages.addMessage(new ApexPages.message(ApexPages.Severity.Info, s));
return new Pagereference(s);
}
}
this compiles fine
2.create a new page , extend the controller ,create button and call method
<apex:page sidebar="false" standardController="Opportunity" extensions="Opportunity" >
<apex:form >
<apex:pageMessages />
{!Opportunity.Name}
<apex:commandButton action="{!doSaveAndNew}" value="Save & New"/>
</apex:form>
</apex:page>
this gives me error "Unknown method 'OpportunityStandardController.doSaveAndNew()'"
I dont know what step I am missing in this process
Any suggestions
The APEX Class extension should not be the same with object name
APEX Class Name
OpportunityController
APEX Page
OpportunityPage
The code should be
<apex:page sidebar="false" standardController="Opportunity" extensions="OpportunityController" >
I think maybe the class name equal the object standard name will error
As Joseph pointed out, the page is trying to access the method in the standard controller 'OpportunityStandardController.doSaveAndNew()' and cannot find it since both the extension and the standard controller are called the same thing and it's just looking in the wrong class.
You probably just need to rename your controller extension to something else. I typically throw "Extension" on the end of the class name so I know what it is for. As an example, maybe something like "OpportunitySaveExtension". Then update your visualforce page to reference the renamed class in the "Extensions" attribute.
extensions="OpportunitySaveExtension"