function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
Karen DargerKaren Darger 

Test Class Chatter Post as Community User

I trigger that prevents a community user if certain conditions about the user's contact record are true, so in my test class I am running as a community user to insert a FeedItem. 

I followed these instructions for creating and testing as a community user (https://developer.salesforce.com/page/Apex_Testing_with_RunAs).
Here is my code that uses the getPortalUser method from above to create the portal user, then insert the post as the user: 
User runningUser = getPortalUser(PortalType.CSPLitePortal, null, true);
Test.StartTest();
system.runas(runningUser){ 
    FeedItem post = new FeedItem();
    post.ParentId = userinfo.getuserid();
    post.Body = 'test post';
    post.NetworkScope=Network.getNetworkId();
    insert post;
}
I get this error ​when inserting the post: INSUFFICIENT_ACCESS_ON_CROSS_REFERENCE_ENTITY, insufficient access rights on cross-reference id

​I know that I need to set the NetworkScope of the post, as it describes in this article (https://help.salesforce.com/apex/HTViewSolution?id=000187667&language=en_US), but Network.getNetworkID() is null. 
How can I retrieve this information in a test class? 
Best Answer chosen by Karen Darger
pconpcon
Understood.  The problem is that your getPortalUser method does not get a user that is associated with a network.  What I would suggest is that you do one of the following:

Option 1
Create a new method that called getNetworkPortalUser this queries the NetworkMember [1] object and finds a MemberId that meets the same criteria as your getPortalUser method does.  You can use the Member.Username / Member.Profile.Name lookups to aid in this.  Then once you find a User that meets the criteria and is in a Network, query them with the same field query you use in getPortalUser but directly against the known MemberId.  Then use that User in your test above.

Option 2
Create a few new methods that create all the data you need.  You'll need to create createNetwork, createPortalUser, and createNetworkMember methods that create a new Network, a new User and a new link between them.  Then use that User in your test.

Option 1 is going to be faster but could be more error prone since you do not have control over every facet.  Option 2 is slower and slightly harder to do, but it allows you to have much more granular control over the data you are using.  Plus it allows you to know all of the expected Id (such as NetworkScope) without having to rely on one already existing.

[1] https://developer.salesforce.com/docs/atlas.en-us.api.meta/api/sforce_api_objects_networkmember.htm

All Answers

pconpcon
I don't know a whole lot about the community users, but I think you'll want to modify your getPortalUser method to make sure it gets a runningUser that is associated with a valid network.  Conversely you could instead create a new User record with all the correct portal user information and then associate them to a network.
Karen DargerKaren Darger
Thanks for the response. To clarify, the getPortalUser does create a new User record. It should have all the correct user information, but it does not explicitly associate them with a network. From what I have tried, I have not been about to explicitly create a network member in the test class, so I am not sure how to set the running users network. 
pconpcon
Understood.  The problem is that your getPortalUser method does not get a user that is associated with a network.  What I would suggest is that you do one of the following:

Option 1
Create a new method that called getNetworkPortalUser this queries the NetworkMember [1] object and finds a MemberId that meets the same criteria as your getPortalUser method does.  You can use the Member.Username / Member.Profile.Name lookups to aid in this.  Then once you find a User that meets the criteria and is in a Network, query them with the same field query you use in getPortalUser but directly against the known MemberId.  Then use that User in your test above.

Option 2
Create a few new methods that create all the data you need.  You'll need to create createNetwork, createPortalUser, and createNetworkMember methods that create a new Network, a new User and a new link between them.  Then use that User in your test.

Option 1 is going to be faster but could be more error prone since you do not have control over every facet.  Option 2 is slower and slightly harder to do, but it allows you to have much more granular control over the data you are using.  Plus it allows you to know all of the expected Id (such as NetworkScope) without having to rely on one already existing.

[1] https://developer.salesforce.com/docs/atlas.en-us.api.meta/api/sforce_api_objects_networkmember.htm
This was selected as the best answer
Karen DargerKaren Darger
Thanks! This did help me get to my answer, but I'll explain further, incase it helps others. When creating a portal user the, NetworkMembership is created automatically (I think based on the community the profile has access to). However, Network.getNetworkID() still returns null when that portal user is the running user. You can query for the network membership and get the ID of the correct network for the user that way. For example: 
//all the set up to create the user
a = new Account(name = 'TEST ACCOUNT');
insert a;

c = new Contact(AccountId = a.id, lastname = 'lastname');
insert c;

Profile p = [select id, name from profile 
                     where usertype = 'CSPLitePortal' limit 1];  
        
String testemail = 'puser000@amamama.com';
User pu = new User(profileId = p.id, username = testemail, email = testemail, 
                           emailencodingkey = 'UTF-8', localesidkey = 'en_US', 
                           languagelocalekey = 'en_US', timezonesidkey = 'America/Los_Angeles', 
                           alias='cspu', lastname='lastname', contactId = c.id);
        
Database.insert(pu);

//get the network membership to get the correct network ID
NetworkMember membership = [SELECT networkID, memberID FROM NetworkMember 
                                                    WHERE memberID = :pu.id];

system.runas(pu){ 
    FeedItem post = new FeedItem(); 
    post.ParentId = userinfo.getuserid(); 
    post.Body = 'test post';   
    post.NetworkScope = membership.networkID;   //set the network ID of the post
    insert post; 
}
Marcel dos SantosMarcel dos Santos

@pcon, I'm facing a problem related to this and what I need is a method like "createNetwork()" to create a network (community) to use in a test class. I don't have an active network in my organization and I don't want to create one just for testing.

The problem is that I don't know how to create a Network object and insert it into the database. I tried to create a Network object in Apex and insert it but it won't work, as it is a System.Network object. I tried also to create it using the Schema class, like sObject ntw = Schema.getGlobalDescribe().get('Network').newSObject() but it won't work either, because I can't use ntw.put('Name', 'TmpNetwork'), saying that Network.Name is not writable.
Do you know how can I create a Network using Apex, or how I could run tests with ConnectApi, for instance, without having a Network with Live status? Thank you.