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, 2019 at 15:53

2 Answers 2

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.

  • 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! Sep 16, 2019 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"}';

You must log in to answer this question.

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