recipes2/internal/http-server/handlers/recipes/recipes_test.go

125 lines
3.8 KiB
Go
Raw Normal View History

2024-01-29 14:01:58 +02:00
package recipes_test
import (
"bytes"
"context"
"encoding/json"
"errors"
"net/http"
"net/http/httptest"
"recipes/internal/domain/models"
"recipes/internal/http-server/handlers/recipes"
"recipes/internal/http-server/handlers/recipes/mocks"
"recipes/internal/lib/logger/handlers/slogdiscard"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestGetRecipesHandler(t *testing.T) {
// cases
cases := []struct {
name string // name of test
page uint // number of page to get
inputBody string // input json
wantBody string // expected output json
wantRespError string // expected error
wantRespStatus string // expected status
storageMockError error // mock error to return
storageTimes int // count of storage calls
recipes []models.Recipe // returned data
}{
{
name: "Success",
page: 1,
inputBody: `{"page": 1}`,
wantBody: "{\"status\":\"OK\",\"recipes\":[{\"id\":1,\"title\":\"title 1\",\"img\":\"1.jpg\",\"ctime\":\"1 час\",\"cal\":\"100 kCal\"},{\"id\":2,\"title\":\"title 2\",\"img\":\"2.jpg\",\"ctime\":\"2 час\",\"cal\":\"200 kCal\"}]}\n",
wantRespStatus: "OK",
storageTimes: 1,
recipes: []models.Recipe{
{
ID: 1,
Title: "title 1",
Image: "1.jpg",
CookingTime: "1 час",
Calories: "100 kCal",
},
{
ID: 2,
Title: "title 2",
Image: "2.jpg",
CookingTime: "2 час",
Calories: "200 kCal",
},
},
},
{
name: "Empty page",
page: 10,
inputBody: `{"page": 10}`,
wantBody: "{\"status\":\"OK\",\"recipes\":null}\n",
wantRespStatus: "OK",
storageTimes: 1,
},
{
name: "Bad data",
inputBody: `{"page": 0}`,
wantBody: "{\"status\":\"Error\",\"error\":\"field Page is a required field\"}\n",
wantRespStatus: "Error",
wantRespError: "field Page is a required field",
storageTimes: 0,
},
{
name: "Broken JSON",
inputBody: `{"page" 1}`,
wantBody: "{\"status\":\"Error\",\"error\":\"failed to decode request\"}\n",
wantRespError: "failed to decode request",
wantRespStatus: "Error",
storageTimes: 0,
},
{
name: "Storage error",
inputBody: `{"page": 1}`,
page: 1,
wantBody: "{\"status\":\"Error\",\"error\":\"failed to get recipes\"}\n",
wantRespError: "failed to get recipes",
wantRespStatus: "Error",
storageMockError: errors.New("SOME ERROR"),
storageTimes: 1,
},
}
for _, tc := range cases {
tc := tc
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
// create storage mock
recipeProviderMock := mocks.NewRecipesProvider(t)
if tc.storageTimes > 0 {
recipeProviderMock.On("GetRecipes", context.Background(), recipes.GetRecipesLimit*(int(tc.page)-1), recipes.GetRecipesLimit).Return(tc.recipes, tc.storageMockError).Times(tc.storageTimes)
}
// create handler
handler := recipes.New(slogdiscard.NewDiscardLogger(), recipeProviderMock)
// http request
req, err := http.NewRequest(http.MethodGet, "/recipes_page", bytes.NewReader([]byte(tc.inputBody)))
require.NoError(t, err)
// create request
rr := httptest.NewRecorder()
handler.ServeHTTP(rr, req)
// compare expected and actual
assert.Equal(t, http.StatusOK, rr.Code)
body := rr.Body.String()
assert.Equal(t, tc.wantBody, body)
var resp recipes.Response
require.NoError(t, json.Unmarshal([]byte(body), &resp))
assert.Equal(t, tc.wantRespError, resp.Error)
assert.Equal(t, tc.wantRespStatus, resp.Status)
assert.Equal(t, tc.recipes, resp.Recipes)
})
}
}