tuna-timer/tuna-timer-api

View on GitHub
web/frontend_handlers_test.go

Summary

Maintainability
A
1 hr
Test Coverage
package web

import (
    "testing"
    "github.com/cleverua/tuna-timer-api/utils"
    "github.com/cleverua/tuna-timer-api/data"
    "github.com/cleverua/tuna-timer-api/models"
    "github.com/nlopes/slack"
    "gopkg.in/mgo.v2/bson"
    "log"
    "gopkg.in/tylerb/is.v1"
    "gopkg.in/mgo.v2"
    "github.com/pavlo/gosuite"
    "net/http"
    "bytes"
    "net/http/httptest"
    "encoding/json"
    "time"
    "github.com/justinas/alice"
    "github.com/dgrijalva/jwt-go"
    "github.com/gorilla/mux"
)

func TestFrontendHandlers(t *testing.T) {
    gosuite.Run(t, &FrontendHandlersTestSuite{Is: is.New(t)})
}

func (s *FrontendHandlersTestSuite) TestAuthenticate(t *testing.T) {
    reqData := map[string]string{ "pid": "pass-for-jwt-generation" }
    body := new(bytes.Buffer)
    json.NewEncoder(body).Encode(reqData)

    req, err := http.NewRequest("POST", "/api/v1/frontend/sessions", body)
    s.Nil(err)
    req.Header.Set("Content-Type", "application/json")

    h := NewFrontendHandlers(s.env, s.session)
    recorder := httptest.NewRecorder()
    handler := http.HandlerFunc(h.Authenticate)
    handler.ServeHTTP(recorder, req)

    resp := JWTResponse{ResponseData: JwtToken{}}
    err = json.Unmarshal(recorder.Body.Bytes(), &resp)
    s.Nil(err)

    verificationToken, err := NewUserToken(s.user.ID.Hex(), s.session)
    s.Nil(err)
    s.Equal(resp.ResponseStatus.Status, "200")
    s.Equal(resp.ResponseData.Token, verificationToken)
}

func (s *FrontendHandlersTestSuite) TestAuthenticateWithWrongPid(t *testing.T) {
    reqData := map[string]string{ "pid": "gIkuvaNzQIHg97ATvDxqgjtO" }
    body := new(bytes.Buffer)
    json.NewEncoder(body).Encode(reqData)

    req, err := http.NewRequest("POST", "/api/v1/frontend/session", body)
    req.Header.Set("Content-Type", "application/json")
    s.Nil(err)

    h := NewFrontendHandlers(s.env, s.session)
    recorder := httptest.NewRecorder()
    handler := http.HandlerFunc(h.Authenticate)
    handler.ServeHTTP(recorder, req)

    resp := JWTResponse{}
    err = json.Unmarshal(recorder.Body.Bytes(), &resp)
    s.Nil(err)
    s.Equal(resp.ResponseStatus.UserMessage, "please login from slack application")
    s.Equal(resp.ResponseStatus.Status, "400")
    s.Equal(resp.ResponseData.Token, "")
    s.Equal(resp.AppInfo["env"], utils.TestEnv)
    s.Equal(resp.AppInfo["version"], s.env.AppVersion)
}

func (s *FrontendHandlersTestSuite) TestTimersData(t *testing.T)  {
    date := time.Now().Format("2006-1-2")
    url := "/api/v1/frontend/timers?startDate=" + date + "&endDate=" + date

    req, err := http.NewRequest("GET", url, nil)
    req.Header.Set("Authorization", "Bearer " + s.userJwt)
    s.Nil(err)

    h := NewFrontendHandlers(s.env, s.session)
    recorder := httptest.NewRecorder()
    s.middlewareChain.ThenFunc(h.TimersData).ServeHTTP(recorder, req)

    resp := TimersResponse{}
    err = json.Unmarshal(recorder.Body.Bytes(), &resp)

    s.Nil(err)
    s.Equal(resp.ResponseStatus.Status, "200")
    s.Equal(resp.AppInfo["env"], utils.TestEnv)
    s.Equal(resp.AppInfo["version"], s.env.AppVersion)
    s.Equal(len(resp.ResponseData), 1)
    s.Equal(resp.ResponseData[0].ID, s.timer.ID)
}

func (s *FrontendHandlersTestSuite) TestTimersDataWithoutDateRange(t *testing.T)  {
    req, err := http.NewRequest("GET", "/api/v1/frontend/timers", nil)
    req.Header.Set("Authorization", "Bearer " + s.userJwt)
    s.Nil(err)

    h := NewFrontendHandlers(s.env, s.session)
    recorder := httptest.NewRecorder()
    s.middlewareChain.ThenFunc(h.TimersData).ServeHTTP(recorder, req)

    resp := TimersResponse{}
    err = json.Unmarshal(recorder.Body.Bytes(), &resp)

    s.Nil(err)
    s.Equal(resp.ResponseStatus.Status, "500")
    s.NotNil(resp.ResponseStatus.DeveloperMessage)
    s.Equal(resp.ResponseStatus.UserMessage, "")
    s.Len(resp.ResponseData, 0)
}

func (s *FrontendHandlersTestSuite) TestTimersDataWithNoExistingUser(t *testing.T)  {
    req, err := http.NewRequest("GET", "/api/v1/frontend/timers?startDate=2016-12-20&endDate=2016-12-22", nil)
    newToken := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
        "user_id":     bson.NewObjectId(),
        "is_team_admin": s.user.SlackUserInfo.IsAdmin,
        "name":         s.user.ExternalUserName,
        "image48":     s.user.SlackUserInfo.Profile.Image48,
        "team_id":     s.team.ID,
        "ext_team_id":     s.team.ExternalTeamID,
        "ext_team_name": s.team.ExternalTeamName,
    })
    token, err := newToken.SignedString([]byte("TODO: Extract me in config/env"))

    req.Header.Set("Authorization", "Bearer " + token)
    s.Nil(err)

    h := NewFrontendHandlers(s.env, s.session)
    recorder := httptest.NewRecorder()
    s.middlewareChain.ThenFunc(h.TimersData).ServeHTTP(recorder, req)

    resp := TimersResponse{}
    err = json.Unmarshal(recorder.Body.Bytes(), &resp)
    s.Nil(err)

    s.Equal(resp.ResponseStatus.Status, "400")
    s.Equal(resp.ResponseStatus.DeveloperMessage, mgo.ErrNotFound.Error())
    s.Equal(resp.ResponseStatus.UserMessage, "please login from slack application")
    s.Len(resp.ResponseData, 0)
}

func (s *FrontendHandlersTestSuite) TestProjectsData(t *testing.T)  {
    req, err := http.NewRequest("GET", "/api/v1/frontend/projects", nil)
    req.Header.Set("Authorization", "Bearer " + s.userJwt)
    s.Nil(err)

    h := NewFrontendHandlers(s.env, s.session)
    recorder := httptest.NewRecorder()
    s.middlewareChain.ThenFunc(h.ProjectsData).ServeHTTP(recorder, req)

    resp := ProjectsResponse{}
    err = json.Unmarshal(recorder.Body.Bytes(), &resp)

    s.Nil(err)
    s.Equal(resp.ResponseStatus.Status, "200")
    s.Equal(resp.AppInfo["env"], utils.TestEnv)
    s.Equal(resp.AppInfo["version"], s.env.AppVersion)
    s.Equal(resp.ResponseData[0].ID, s.team.Projects[0].ID)
    s.Equal(resp.ResponseData[0].ExternalProjectID, s.team.Projects[0].ExternalProjectID)
    s.Equal(resp.ResponseData[0].ExternalProjectName, s.team.Projects[0].ExternalProjectName)
}

func (s *FrontendHandlersTestSuite) TestProjectsDataWithNoExistedUser(t *testing.T)  {
    req, err := http.NewRequest("GET", "/api/v1/frontend/projects", nil)
    newToken := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
        "user_id":     bson.NewObjectId(),
        "is_team_admin": s.user.SlackUserInfo.IsAdmin,
        "name":         s.user.ExternalUserName,
        "image48":     s.user.SlackUserInfo.Profile.Image48,
        "team_id":     s.team.ID,
        "ext_team_id":     s.team.ExternalTeamID,
        "ext_team_name": s.team.ExternalTeamName,
    })
    token, err := newToken.SignedString([]byte("TODO: Extract me in config/env"))

    req.Header.Set("Authorization", "Bearer " + token)
    s.Nil(err)

    h := NewFrontendHandlers(s.env, s.session)
    recorder := httptest.NewRecorder()
    s.middlewareChain.ThenFunc(h.ProjectsData).ServeHTTP(recorder, req)
    resp := ProjectsResponse{}
    err = json.Unmarshal(recorder.Body.Bytes(), &resp)

    s.Nil(err)
    s.Equal(resp.ResponseStatus.Status, "400")
    s.Equal(resp.ResponseStatus.DeveloperMessage, mgo.ErrNotFound.Error())
    s.Equal(resp.AppInfo["env"], utils.TestEnv)
    s.Equal(resp.AppInfo["version"], s.env.AppVersion)
}

func (s *FrontendHandlersTestSuite) TestCreateTimer(t *testing.T)  {
    // It should create new timer, stop active timer and return current day Timers for User
    newTimer := models.Timer{
        TaskName:   "New task name",
        TeamUserID: s.user.ID.Hex(),
        TeamID:     s.team.ID.Hex(),
        ProjectID:  bson.NewObjectId().Hex(),
        ProjectExternalID:  "external-project-id",
        ProjectExternalName: "external-project-name",
        Minutes: 30,
    }
    body := new(bytes.Buffer)
    json.NewEncoder(body).Encode(newTimer)

    req, err := http.NewRequest("POST", "/api/v1/frontend/timers", body)
    s.Nil(err)
    req.Header.Set("Authorization", "Bearer " + s.userJwt)
    req.Header.Set("Content-Type", "application/json")

    h := NewFrontendHandlers(s.env, s.session)
    recorder := httptest.NewRecorder()
    s.middlewareChain.ThenFunc(h.CreateTimer).ServeHTTP(recorder, req)

    resp := TimersResponse{}
    err = json.Unmarshal(recorder.Body.Bytes(), &resp)

    s.Nil(err)
    s.Equal(resp.ResponseStatus.Status, "200")
    s.Equal(resp.AppInfo["env"], utils.TestEnv)
    s.Equal(resp.AppInfo["version"], s.env.AppVersion)

    // Check response timers data
    s.Len(resp.ResponseData, 2)

    // Check for first timer completed
    s.Equal(resp.ResponseData[0].ID, s.timer.ID)
    s.Equal(resp.ResponseData[0].Minutes, 20)
    s.NotNil(resp.ResponseData[0])

    // Check new timers data
    s.Equal(resp.ResponseData[1].TaskName, newTimer.TaskName)
    s.Equal(resp.ResponseData[1].TeamUserID, newTimer.TeamUserID)
    s.Equal(resp.ResponseData[1].ProjectID, newTimer.ProjectID)
    s.Equal(resp.ResponseData[1].ProjectExternalID, newTimer.ProjectExternalID)
    s.Equal(resp.ResponseData[1].ProjectExternalName, newTimer.ProjectExternalName)
    s.Equal(resp.ResponseData[1].Minutes, 0)
    s.Equal(resp.ResponseData[1].ActualMinutes, 0)
    s.Equal(resp.ResponseData[1].TeamID, s.user.TeamID)
}

func (s *FrontendHandlersTestSuite) TestUpdateTimer(t *testing.T)  {
    timersData := models.Timer{
        ID: s.timer.ID,
        TaskName:   "New task name",
        ProjectID:  bson.NewObjectId().Hex(),
        ProjectExternalID:  "external-project-id",
        ProjectExternalName: "external-project-name",
        Minutes: 25,
        Edits: []*models.TimeEdit{
            {TeamUserID: s.user.ID.Hex(), CreatedAt: time.Now(), Minutes: 10},
        },
    }
    body := new(bytes.Buffer)
    json.NewEncoder(body).Encode(timersData)

    req, err := http.NewRequest("PUT", "/api/v1/frontend/timers", body)
    s.Nil(err)
    req.Header.Set("Authorization", "Bearer " + s.userJwt)
    req.Header.Set("Content-Type", "application/json")

    h := NewFrontendHandlers(s.env, s.session)
    recorder := httptest.NewRecorder()
    s.middlewareChain.ThenFunc(h.UpdateTimer).ServeHTTP(recorder, req)

    resp := TimerResponse{}
    err = json.Unmarshal(recorder.Body.Bytes(), &resp)

    s.Nil(err)
    s.Equal(resp.ResponseStatus.Status, "200")
    s.Equal(resp.AppInfo["env"], utils.TestEnv)
    s.Equal(resp.AppInfo["version"], s.env.AppVersion)
    s.Equal(resp.ResponseData.ID, s.timer.ID)
    s.Equal(resp.ResponseData.TaskName, timersData.TaskName)
    s.Equal(resp.ResponseData.TeamUserID, s.timer.TeamUserID)
    s.Equal(resp.ResponseData.ProjectID, timersData.ProjectID)
    s.Equal(resp.ResponseData.ProjectExternalID, timersData.ProjectExternalID)
    s.Equal(resp.ResponseData.ProjectExternalName, timersData.ProjectExternalName)
    s.Equal(resp.ResponseData.TeamID, s.user.TeamID)
    // Check calculation of timers edits
    s.NotEqual(resp.ResponseData.Minutes, 25)
    s.Equal(resp.ResponseData.Minutes, 30)
}

func (s *FrontendHandlersTestSuite) TestUpdateTimerWithNoExistingTimer(t *testing.T)  {
    timersData := models.Timer{
        ID: bson.NewObjectId(),
        TaskName:   "New task name",
        ProjectID:  bson.NewObjectId().Hex(),
        ProjectExternalID:  "external-project-id",
        ProjectExternalName: "external-project-name",
    }
    body := new(bytes.Buffer)
    json.NewEncoder(body).Encode(timersData)

    req, err := http.NewRequest("PUT", "/api/v1/frontend/timers", body)
    s.Nil(err)
    req.Header.Set("Authorization", "Bearer " + s.userJwt)
    req.Header.Set("Content-Type", "application/json")

    h := NewFrontendHandlers(s.env, s.session)
    recorder := httptest.NewRecorder()
    s.middlewareChain.ThenFunc(h.UpdateTimer).ServeHTTP(recorder, req)

    resp := TimerResponse{}
    err = json.Unmarshal(recorder.Body.Bytes(), &resp)

    s.Nil(err)
    s.Equal(resp.ResponseStatus.Status, "500")
    s.Equal(resp.AppInfo["env"], utils.TestEnv)
    s.Equal(resp.AppInfo["version"], s.env.AppVersion)
    s.Equal(resp.ResponseStatus.DeveloperMessage, "update forbidden")
}

func (s *FrontendHandlersTestSuite) TestUpdateTimerStopAction(t *testing.T)  {
    body := new(bytes.Buffer)
    json.NewEncoder(body).Encode(models.Timer{})

    req, err := http.NewRequest("PUT", "/api/v1/frontend/timers?stop_timer=true", body)
    s.Nil(err)
    req.Header.Set("Authorization", "Bearer " + s.userJwt)
    req.Header.Set("Content-Type", "application/json")

    h := NewFrontendHandlers(s.env, s.session)
    recorder := httptest.NewRecorder()
    s.middlewareChain.ThenFunc(h.UpdateTimer).ServeHTTP(recorder, req)

    resp := TimerResponse{}
    err = json.Unmarshal(recorder.Body.Bytes(), &resp)

    s.Nil(err)
    s.Equal(resp.ResponseStatus.Status, "200")
    s.Equal(resp.AppInfo["env"], utils.TestEnv)
    s.Equal(resp.AppInfo["version"], s.env.AppVersion)
    s.Equal(resp.ResponseData.ID, s.timer.ID)
    s.Equal(resp.ResponseData.Minutes, 20)
    s.NotNil(resp.ResponseData.FinishedAt)
}

func (s *FrontendHandlersTestSuite) TestUpdateTimerStopAlreadyStoppedTimer(t *testing.T)  {
    timerService := data.NewTimerService(s.session)
    err := timerService.StopTimer(s.timer)
    s.Nil(err)

    body := new(bytes.Buffer)
    json.NewEncoder(body).Encode(models.Timer{})

    req, err := http.NewRequest("PUT", "/api/v1/frontend/timers?stop_timer=true", body)
    s.Nil(err)
    req.Header.Set("Authorization", "Bearer " + s.userJwt)
    req.Header.Set("Content-Type", "application/json")

    h := NewFrontendHandlers(s.env, s.session)
    recorder := httptest.NewRecorder()
    s.middlewareChain.ThenFunc(h.UpdateTimer).ServeHTTP(recorder, req)

    resp := TimerResponse{}
    err = json.Unmarshal(recorder.Body.Bytes(), &resp)

    s.Nil(err)
    s.Equal(resp.ResponseStatus.Status, "400")
    s.Equal(resp.ResponseStatus.DeveloperMessage, mgo.ErrNotFound.Error())
    s.Equal(resp.ResponseStatus.UserMessage, "already stopped")
}

func (s *FrontendHandlersTestSuite) TestDeleteTimer(t *testing.T) {
    router := mux.NewRouter()
    h := NewFrontendHandlers(s.env, s.session)
    router.Handle("/api/v1/frontend/timers/{id}", s.middlewareChain.ThenFunc(h.DeleteTimer)).Methods("DELETE")
    ts := httptest.NewServer(router)
    defer ts.Close()

    req, _ := http.NewRequest("DELETE", ts.URL + "/api/v1/frontend/timers/" + s.timer.ID.Hex(), nil)
    req.Header.Set("Authorization", "Bearer " + s.userJwt)
    req.Header.Set("Content-Type", "application/json")

    resp, err := http.DefaultClient.Do(req)
    s.Nil(err)

    respBody := ResponseBody{}
    err = json.NewDecoder(resp.Body).Decode(&respBody)
    s.Nil(err)
    s.Equal(respBody.ResponseStatus.Status, "200")
    s.Zero(respBody.ResponseStatus.DeveloperMessage)
    s.Equal(respBody.ResponseStatus.UserMessage, "successfully deleted")

    // Test with not existing timer id
    req, _ = http.NewRequest("DELETE", ts.URL + "/api/v1/frontend/timers/" + bson.NewObjectId().Hex(), nil)
    req.Header.Set("Authorization", "Bearer " + s.userJwt)
    req.Header.Set("Content-Type", "application/json")

    resp, err = http.DefaultClient.Do(req)
    s.Nil(err)

    respBody = ResponseBody{}
    err = json.NewDecoder(resp.Body).Decode(&respBody)
    s.Nil(err)
    s.Equal(respBody.ResponseStatus.Status, "500")
    s.Equal(respBody.ResponseStatus.DeveloperMessage, "not found")
    s.Zero(respBody.ResponseStatus.UserMessage)
}

func (s *FrontendHandlersTestSuite) TestDeleteTimerWithForeignUser(t *testing.T) {
    router := mux.NewRouter()
    h := NewFrontendHandlers(s.env, s.session)
    router.Handle("/api/v1/frontend/timers/{id}", s.middlewareChain.ThenFunc(h.DeleteTimer)).Methods("DELETE")
    ts := httptest.NewServer(router)
    defer ts.Close()

    userRepository := data.NewUserRepository(s.session)
    user := &models.TeamUser{
        TeamID:           s.team.ID.Hex(),
        ExternalUserID:   "user-id",
        ExternalUserName: "name",
        SlackUserInfo:    &slack.User{
            IsAdmin:  false,
        },
    }

    _, err := userRepository.Save(user)
    s.Nil(err)

    userJwt, err := NewUserToken(user.ID.Hex(), s.session)
    s.Nil(err)

    req, _ := http.NewRequest("DELETE", ts.URL + "/api/v1/frontend/timers/" + s.timer.ID.Hex(), nil)
    req.Header.Set("Authorization", "Bearer " + userJwt)
    req.Header.Set("Content-Type", "application/json")

    resp, err := http.DefaultClient.Do(req)
    s.Nil(err)

    respBody := ResponseBody{}
    err = json.NewDecoder(resp.Body).Decode(&respBody)
    s.Nil(err)
    s.Equal(respBody.ResponseStatus.Status, "500")
    s.Equal(respBody.ResponseStatus.DeveloperMessage, "delete forbidden")
    s.Zero(respBody.ResponseStatus.UserMessage)
}

func (s *FrontendHandlersTestSuite) TestMonthStatistic(t *testing.T)  {
    startDate := utils.PT("2016 Dec 01 00:00:00")
    finished := startDate.Add(time.Minute * 30)
    timerRepository := data.NewTimerRepository(s.session)
    timerRepository.CreateTimer(&models.Timer{
        ID:            bson.NewObjectId(),
        TeamID:            "team",
        ProjectID:        "project",
        ProjectExternalName:    "project_name",
        TeamUserID:        s.user.ID.Hex(),
        CreatedAt:        startDate.Add(time.Hour * 1),
        Minutes:        30,
        FinishedAt:        &finished,
    })

    req, err := http.NewRequest("GET", "/api/v1/frontend/month_statistics?date=2016-12-1", nil)
    s.Nil(err)
    req.Header.Set("Authorization", "Bearer " + s.userJwt)
    req.Header.Set("Content-Type", "application/json")

    h := NewFrontendHandlers(s.env, s.session)
    recorder := httptest.NewRecorder()
    s.middlewareChain.ThenFunc(h.MonthStatistics).ServeHTTP(recorder, req)

    resp := UserStatisticsResponse{}
    err = json.Unmarshal(recorder.Body.Bytes(), &resp)

    s.Nil(err)
    s.Equal(resp.ResponseStatus.Status, "200")
    s.Equal(resp.AppInfo["env"], utils.TestEnv)
    s.Equal(resp.AppInfo["version"], s.env.AppVersion)
    s.NotNil(resp.ResponseData[0])
    s.Equal(resp.ResponseData[0].Day, 1)
    s.Equal(resp.ResponseData[0].Minutes, 30)
    s.Equal(resp.ResponseData[0].ProjectsNames[0], "project_name")
    s.Len(resp.ResponseData, 1)
}

// =================== TEST setup =================== //
type FrontendHandlersTestSuite struct {
    *is.Is
    env     *utils.Environment
    session *mgo.Session
    user    *models.TeamUser
    pass    *models.Pass
    team    *models.Team
    timer     *models.Timer
    userJwt string
    secureCTX *SecureContext
    middlewareChain alice.Chain
}

func (s *FrontendHandlersTestSuite) SetUpSuite() {
    e := utils.NewEnvironment(utils.TestEnv, "1.0.0")

    session, err := utils.ConnectToDatabase(e.Config)
    if err != nil {
        log.Fatal("Failed to connect to DB!")
    }

    s.session = session.Clone()
    e.MigrateDatabase(session)
    s.env = e

    s.secureCTX = &SecureContext{
        Origin:  s.env.Config.UString("origin.url"),
        Session: s.session,
        Env:      s.env,
    }
    s.middlewareChain = alice.New(
        s.secureCTX.CorsMiddleware,
        JWTMiddleware,
        s.secureCTX.CurrentUserMiddleware)
}

func (s *FrontendHandlersTestSuite) TearDownSuite() {
    s.session.Close()
}

func (s *FrontendHandlersTestSuite) SetUp() {
    //Clear Database
    utils.TruncateTables(s.session)

    //Seed Database
    passRepository := data.NewPassRepository(s.session)
    userRepository := data.NewUserRepository(s.session)
    teamRepository := data.NewTeamRepository(s.session)
    timerRepository := data.NewTimerRepository(s.session)
    var err error

    //Create team with project
    s.team, err = teamRepository.CreateTeam("ExtTeamID", "ExtTeamName")
    s.Nil(err)
    err = teamRepository.AddProject(s.team, "external-project-id", "external-project-name")
    s.Nil(err)
    s.team, _ = teamRepository.FindByID(s.team.ID.Hex())

    //Create user
    s.user = &models.TeamUser{
        TeamID:           s.team.ID.Hex(),
        ExternalUserID:   "ext-user-id",
        ExternalUserName: "user-name",
        SlackUserInfo:    &slack.User{
            IsAdmin: true,
        },
    }
    _, err = userRepository.Save(s.user)
    s.Nil(err)

    //Create pass
    s.pass = &models.Pass{
        ID:           bson.NewObjectId(),
        Token:        "pass-for-jwt-generation",
        TeamUserID:   s.user.ID.Hex(),
        CreatedAt:    time.Now(),
        ExpiresAt:    time.Now().Add(5 * time.Minute),
    }
    err = passRepository.Insert(s.pass)
    s.Nil(err)

    //Create timer
    s.timer, err = timerRepository.CreateTimer(
        &models.Timer{
            ID:             bson.NewObjectId(),
            TeamID:         s.team.ID.Hex(),
            ProjectID:      "project",
            TeamUserID:     s.user.ID.Hex(),
            CreatedAt:      time.Now().Add(-20 * time.Minute),
            Minutes:        20,
            ActualMinutes:  20,
    })
    s.Nil(err)

    //Generate user JWT
    s.userJwt, err = NewUserToken(s.user.ID.Hex(), s.session)
    s.Nil(err)
}

func (s *FrontendHandlersTestSuite) TearDown() {}