I am writing a simple api callout for Tsheets, and its working just fine, now when writing the test class, its failing on the line "object results = Meta.get('results')".

The error is: System.JSONException: Unexpected character ('y' (code 121)): expected a valid value (number, String, array, object, 'true', 'false' or 'null') at input location [1,2]

Here is the Apex Class:

public class TSheetsGetTimesheets {

public void getTimesheets(){

    TSheetsLogin__c tc = TSheetsLogin__c.getorgdefaults();

    string AuthToken = tc.OAuth_Token__c;     

    Date d = Date.today();

    String ToDate = string.valueOf(d);

    Date JobDate = tc.Last_Sync_Run__c;

    String LastRun = string.valueOf(JobDate);   

    string EndPoint = 'https://rest.tsheets.com/api/v1/timesheets?start_date='+ LastRun +'&end_date='+ ToDate +'&on_the_clock=no&';        

    Http http = new Http();

    HttpRequest req = new HttpRequest();

    req.setHeader('Authorization', 'Bearer ' + AuthToken);

    HttpResponse res = http.send(req);      

    String JsonStr = res.getBody(); 

    Map<String, Object> meta = (Map<String, Object>) JSON.deserializeUntyped(JsonStr);

    object results = meta.get('results');

    string s = json.serializepretty(results);

    Map<String, Object> o = (Map<String, Object>) JSON.deserializeUntyped(s);

    string s1 = json.serializepretty(o.get('timesheets'));

    Map<String, Object> o1 = (Map<String, Object>) JSON.deserializeUntyped(s1);

    Map<String,Map<String,Object>> mapTimesheets = new Map<String,Map<String,Object>>();

    for(string thisTimesheetId : o1.keySet()){
        string stringThisTimesheet = json.serializepretty(o1.get(thisTimesheetId));
        Map<String, Object> mapThisTimesheet = (Map<String, Object>) JSON.deserializeUntyped(stringThisTimesheet);
        //if(thisTimesheetId == '173162158'){
        If(mapTimesheets.size() > 0 ) {
            timesheetData tds = new timesheetData(mapTimesheets.get(thisTimesheetId));
            TSheets_Time_Entry__c tse = new TSheets_Time_Entry__c();

            tse.Time_Entry_ID__c = tds.timesheetId; 
            tse.User_ID__c = tds.userId; 
            tse.Name = tds.jobcodeId; 
            tse.Start__c = tds.startDatetime; 
            tse.End__c = tds.endDatetime; 
            tse.TSheetsDuration__c = tds.duration;
            tse.Type__c = tds.type; 

            insert tse;         


    tc.Last_Sync_Run__c = d;
    update tc;


public class timesheetData{
    public string timesheetId;
    public string userId;
    public string jobcodeId;
    public datetime startDatetime;
    public datetime endDatetime;
    public integer duration;
    public string type;
    public string notes;

    public timesheetData(object o){
        string serializedObject = json.serializepretty(o);
        Map<String, Object> mapObject = (Map<String, Object>) JSON.deserializeUntyped(serializedObject);
        timesheetId = string.valueOf(mapObject.get('id'));
        userId = string.valueOf(mapObject.get('user_id'));
        jobcodeId = string.valueOf(mapObject.get('jobcode_id'));
        startDatetime = convertDateTime(string.valueOf(mapObject.get('start')));
        endDatetime = convertDateTime(string.valueOf(mapObject.get('end')));
        duration = integer.valueOf(mapObject.get('duration'));
        type = string.valueOf(mapObject.get('type'));
        notes = string.valueOf(mapObject.get('notes'));

public static Datetime convertDateTime(String s){
    integer startYear = integer.valueof(s.mid(0,4));
    integer startMonth = integer.valueof(s.mid(5,2));
    integer startDay = integer.valueof(s.mid(8,2));
    integer startHour = integer.valueof(s.mid(11,2));
    integer startMin = integer.valueof(s.mid(14,2));
    integer startSec = integer.valueof(s.mid(17,2));
    Datetime convertedDateTime = Datetime.newInstance(startYear, startMonth, startDay, startHour, startMin, startSec);
    return convertedDateTime;


and here is my test method:

private class test_getTimesheets {

    static testmethod void test_getTimesheets_UseCase1() {

        TSheetsGetTimesheets tgts = New TSheetsGetTimesheets(); 

        Test.setMock(HttpCalloutMock.class, new RestMock());




      private class RestMock implements HttpCalloutMock {

        public HTTPResponse respond(HTTPRequest req) {
            String fullJson = 'your Json Response';

            HTTPResponse res = new HTTPResponse();
            res.setHeader('Content-Type', 'text/json');
            return res;

  • While it's not the cause of this specific problem, debugging tests that use seealldata=true is often an exercise in futility, and using that annotation is bad practice in all but the tiniest slice of circumstances. Consider removing it and generating your test data. – David Reed Sep 15 '19 at 15:53
String fullJson = 'your Json Response';

You must change this line to valid JSON. You can use the timesheetData class to help build the appropriate JSON string using JSON.serialize.

| improve this answer | |
  • 1
    Well this is why one needs to not code into the wee hours of the morning with little to eat or drink. I see what you mean now. Thank you! – Daniel Bauer Sep 16 '19 at 13:20

Json string does not looks good. Try to place the json string in Static Resource and json string should be the following as per your apex code.

String fullJson = '{"results":"your Json Response"}';
| improve this answer | |

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.