Implemented the Organization Chart feature to create customer organizational
This commit is contained in:
114
tests/accountContact.test.cjs
Normal file
114
tests/accountContact.test.cjs
Normal file
@@ -0,0 +1,114 @@
|
||||
const { test } = require("node:test");
|
||||
const assert = require("node:assert/strict");
|
||||
const fs = require("node:fs");
|
||||
const vm = require("node:vm");
|
||||
const factory = new vm.Script(fs.readFileSync("src/services/fusion/account-contact.js", "utf8") + "\ncreateFusionAccountContact").runInNewContext();
|
||||
function setup(response) {
|
||||
const calls=[], logs=[], failures=[], window={}; let tokens=0;
|
||||
const service=factory({ environment:{window, async fetch(url,options) {
|
||||
assert.equal(this,window,"Native fetch must use Window as its receiver");
|
||||
calls.push({url,options}); return response instanceof Response ? response : Response.json(response);
|
||||
}}, getToken:async()=>{tokens++;return "test-relay-token";},logRequestStart:entry=>{logs.push(entry);return entry;},
|
||||
logRequestSuccess:()=>{}, logRequestFailure:(_,error)=>failures.push(error),readResponseBodyForDebug:response=>response.clone().text() });
|
||||
return {service,calls,logs,failures,tokens:()=>tokens};
|
||||
}
|
||||
|
||||
test("contact opportunities uses the person's PartyNumber, paging and contact-query headers",async()=>{
|
||||
const h=setup({items:[{OptyNumber:"A56DLD"}],hasMore:true,totalResults:12});
|
||||
const data=await h.service.requestOpportunitiesByContact("18725565",5);
|
||||
assert.equal(data.items[0].OptyNumber,"A56DLD");
|
||||
const {url,options}=h.calls[0], parsed=new URL(url);
|
||||
assert.equal(parsed.searchParams.get("q"),"(OpportunityContact.ContactPartyNumber='18725565')");
|
||||
assert.equal(parsed.searchParams.get("offset"),"5");assert.equal(parsed.searchParams.get("limit"),"5");
|
||||
assert.equal(options.method,"GET");assert.equal(options.headers.Authorization,"Bearer test-relay-token");
|
||||
assert.equal(options.headers.Preference,"transient");assert.equal(options.headers.Origin,"https://eeho.fa.us2.oraclecloud.com");
|
||||
assert.equal(h.logs[0].name,"requestOpportunitiesByContact");
|
||||
assert.equal(h.logs[0].url,url);
|
||||
assert.ok(url.includes("q=%28OpportunityContact.ContactPartyNumber%3D%2718725565%27%29"));
|
||||
await assert.rejects(h.service.requestOpportunitiesByContact(undefined),/PartyNumber/);
|
||||
assert.equal(h.calls.length,1);
|
||||
});
|
||||
|
||||
test("contact identity lookup uses exact PartyId without name keyword ranking",async()=>{
|
||||
const h=setup({items:[{PartyId:"123",PartyName:"New Name",PartyNumber:"789"}]});
|
||||
const contacts=await h.service.requestQueryAccountContact(456,"Old Name",()=>true,"123");
|
||||
const body=JSON.parse(h.calls[0].options.body);
|
||||
assert.equal(body.keywords,"");assert.deepEqual(body.q.criteria.at(-1),{attribute:"PartyId",op:"$eq",value:"123"});
|
||||
assert.equal(contacts[0].PartyNumber,"789");
|
||||
});
|
||||
|
||||
test("contact opportunity query preserves an alphanumeric PartyNumber",async()=>{
|
||||
const h=setup({items:[],hasMore:false});
|
||||
await h.service.requestOpportunitiesByContact("A4KCS2P");
|
||||
assert.equal(new URL(h.calls[0].url).searchParams.get("q"),"(OpportunityContact.ContactPartyNumber='A4KCS2P')");
|
||||
assert.equal(h.logs[0].metadata.partyNumber,"A4KCS2P");
|
||||
});
|
||||
|
||||
test("opportunities resolution failures are logged before any HTTP request",async()=>{
|
||||
const h=setup({items:[]});
|
||||
await assert.rejects(h.service.requestOpportunitiesByContact(null,0,{contactPartyId:"123",contactName:"Alex",resolvePartyNumber:async()=>undefined}),/HTTP request was not sent/);
|
||||
assert.equal(h.calls.length,0);assert.equal(h.tokens(),0);
|
||||
assert.equal(h.logs[0].name,"resolveContactForOpportunities");assert.equal(h.logs[0].method,"LOCAL");assert.equal(h.logs[0].metadata.httpRequestSent,false);
|
||||
assert.equal(h.logs[0].metadata.contactPartyId,"123");assert.equal(h.failures.length,1);
|
||||
await assert.rejects(h.service.requestOpportunitiesByContact(null,0,{resolvePartyNumber:async()=>{throw new Error("Contact query failed");}}),/Contact query failed/);
|
||||
assert.equal(h.failures.length,2);
|
||||
});
|
||||
test("contact search posts the specified payload with dynamic PartyId, keywords and Token Relay bearer token",async()=>{
|
||||
const h=setup({items:[{PartyId:123,PartyName:"Same Name",JobTitle:"Architect"},{PartyId:456,PartyName:"Same Name",JobTitle:null}]});
|
||||
const result=await h.service.requestQueryAccountContact("100000810210835",'Alex "Cloud"');
|
||||
assert.equal(result.length,2); assert.equal(result[0].PartyId,"123");
|
||||
const {url,options}=h.calls[0]; assert.ok(url.endsWith("/crmRestApi/searchResources/latest/custom-actions/queries"));
|
||||
assert.equal(options.method,"POST");assert.equal(options.headers.Authorization,"Bearer test-relay-token");
|
||||
assert.equal(options.headers["Content-Type"],"application/json");assert.equal(options.credentials,"include");
|
||||
assert.equal(options.headers.Preference,"transient");
|
||||
assert.equal(options.headers.Origin,"https://eeho.fa.us2.oraclecloud.com");
|
||||
const fields=["PartyName","PrimaryEmail.EmailAddress","JobTitle","PrimaryAccount.PartyName","PartyId","PartyNumber"];
|
||||
assert.deepEqual(JSON.parse(options.body),{aggregationResults:false,skipInValidFields:true,skipHiddenFromUIFields:true,language:"en",onlyData:true,
|
||||
keywords:'Alex "Cloud"',entity:"Contact",fields,keywordsFields:fields,
|
||||
q:{op:"$and",criteria:[{op:"$or",innerQuery:true,criteria:[{attribute:"PrimaryAccount.PartyId",op:"$eq",value:100000810210835}]}],innerQuery:true},
|
||||
sort:[{attribute:"_score",direction:"descending"}],limit:15,offset:0});
|
||||
assert.equal(h.logs[0].name,"requestQueryAccountContact");assert.equal(h.calls.length,1);
|
||||
});
|
||||
test("contact search skips blank or obsolete queries and never sends a query without an account",async()=>{
|
||||
const h=setup({items:[]});
|
||||
await h.service.requestQueryAccountContact(123," ");
|
||||
await h.service.requestQueryAccountContact(123,"Alex",()=>false);
|
||||
await assert.rejects(h.service.requestQueryAccountContact(undefined,"Alex"),/PartyId/);
|
||||
assert.equal(h.calls.length,0);assert.equal(h.tokens(),0);
|
||||
});
|
||||
test("contact search reports HTTP and malformed-response errors",async()=>{
|
||||
for(const response of [new Response("Denied",{status:401}),{items:null}]){
|
||||
const h=setup(response);await assert.rejects(h.service.requestQueryAccountContact(123,"Alex"));
|
||||
assert.equal(h.calls.length,1);assert.equal(h.failures.length,1);
|
||||
}
|
||||
});
|
||||
|
||||
test("contact creation maps account, phone and mutually exclusive contact preferences", async()=>{
|
||||
for (const preference of ["none", "deny", "allow"]) {
|
||||
const h=setup({PartyId:321});
|
||||
await h.service.requestPersistContact({PartyId:123,PartyNumber:"456"},{firstName:" Alex ",lastName:" Test ",jobTitle:"Engineer",email:"alex@example.test",
|
||||
emailConsent:preference,workConsent:preference,mobileConsent:preference,workPhone:"3131313131",workCountry:"55",workExtension:"3131",mobilePhone:"31999999999",mobileCountry:"55"});
|
||||
const {url,options}=h.calls[0], payload=JSON.parse(options.body);
|
||||
assert.ok(url.endsWith("/contacts?onlyData=true")); assert.equal(options.method,"POST");
|
||||
assert.equal(options.headers.Authorization,"Bearer test-relay-token");assert.equal(options.headers.Origin,"https://eeho.fa.us2.oraclecloud.com");
|
||||
assert.equal(payload.AccountPartyId,"123");assert.equal(payload.AccountPartyNumber,"456");assert.equal(payload.FirstName,"Alex");
|
||||
assert.equal(payload.RawWorkPhoneNumber,"55-3131313131");assert.equal(payload.WorkPhoneExtension,"3131");assert.equal(payload.RawMobileNumber,"55-31999999999");
|
||||
for(const key of ["DoCallWorkPhoneFlag","DoCallMobilePhoneFlag","DoContactEmailFlag"]) assert.equal(payload[key],preference==="none"?undefined:preference==="allow");
|
||||
for(const key of ["DoNotCallWorkPhoneFlag","DoNotCallMobileFlag","DoNotContactEmailFlag"]) assert.equal(payload[key],preference==="none"?undefined:preference==="deny");
|
||||
assert.equal(h.logs[0].name,"requestPersistContact");
|
||||
}
|
||||
});
|
||||
|
||||
test("contact creation reports failed POST without automatic retries",async()=>{
|
||||
const h=setup(new Response("Denied",{status:403}));
|
||||
await assert.rejects(h.service.requestPersistContact({PartyId:123,PartyNumber:"456"},{firstName:"Alex",lastName:"Test",jobTitle:"",email:"alex@example.test",workPhone:"",workCountry:"",workExtension:"",mobilePhone:"",mobileCountry:""}),/403/);
|
||||
assert.equal(h.calls.length,1);assert.equal(h.failures.length,1);
|
||||
});
|
||||
|
||||
test("contact creation sends directly and omits empty optional fields", async()=>{
|
||||
const values={firstName:"Alex",lastName:"Test",jobTitle:"",email:"alex@example.test",workPhone:"",workCountry:"",workExtension:"",mobilePhone:"",mobileCountry:""};
|
||||
const h=setup({PartyId:321});
|
||||
await h.service.requestPersistContact({PartyId:123,PartyNumber:"456"},values);
|
||||
assert.equal(h.calls.length,1);assert.equal(h.tokens(),1);
|
||||
assert.deepEqual(JSON.parse(h.calls[0].options.body),{FirstName:"Alex",LastName:"Test",AccountPartyId:"123",AccountPartyNumber:"456",Type:"ZCA_CONTACT",EmailAddress:"alex@example.test"});
|
||||
});
|
||||
Reference in New Issue
Block a user