diff --git a/internal/app/api/api.go b/internal/app/api/api.go index 65bc1ff..4662fab 100644 --- a/internal/app/api/api.go +++ b/internal/app/api/api.go @@ -1,7 +1,6 @@ package api import ( - "errors" "fmt" jwt "github.com/appleboy/gin-jwt/v2" "github.com/gin-gonic/gin" @@ -9,7 +8,7 @@ import ( "pinman/internal/app/api/league" "pinman/internal/app/api/location" "pinman/internal/app/api/user" - "reflect" + "pinman/internal/utils" ) type AuthHandlers struct { @@ -36,24 +35,13 @@ func NewServer(db *gorm.DB, authMiddleware *jwt.GinJWTMiddleware) *Server { Refresh: authMiddleware.RefreshHandler, }, } - if err := checkFieldsForNil(server); err != nil { + if err := utils.CheckFieldsForNil(server); err != nil { panic(fmt.Errorf("failed to create server: %w", err)) } return server } -func checkFieldsForNil(s *Server) error { - serverValue := reflect.ValueOf(*s) - for i := 0; i < serverValue.NumField(); i++ { - fieldValue := serverValue.Field(i) - if fieldValue.Kind() == reflect.Ptr && fieldValue.IsNil() { - return errors.New(fmt.Sprint("field ", serverValue.Type().Field(i).Name, " is nil")) - } - } - return nil -} - func (s *Server) PostAuthLogin(c *gin.Context) { s.AuthHandlers.Login(c) } diff --git a/internal/app/api/api_suite_test.go b/internal/app/api/api_suite_test.go new file mode 100644 index 0000000..165830f --- /dev/null +++ b/internal/app/api/api_suite_test.go @@ -0,0 +1,26 @@ +package api_test + +import ( + jwt "github.com/appleboy/gin-jwt/v2" + "gorm.io/gorm" + "pinman/internal/app/api" + "testing" + + "github.com/onsi/ginkgo/v2" + "github.com/onsi/gomega" +) + +func TestApi(t *testing.T) { + gomega.RegisterFailHandler(ginkgo.Fail) + ginkgo.RunSpecs(t, "Api Suite") +} + +var _ = ginkgo.Describe("NewServer", func() { + ginkgo.It("should not return nil", func() { + server := api.NewServer( + &gorm.DB{}, + &jwt.GinJWTMiddleware{}, + ) + gomega.Expect(server).NotTo(gomega.BeNil()) + }) +}) diff --git a/internal/utils/checkFieldsForNil.go b/internal/utils/checkFieldsForNil.go new file mode 100644 index 0000000..a9c9a1f --- /dev/null +++ b/internal/utils/checkFieldsForNil.go @@ -0,0 +1,23 @@ +package utils + +import ( + "errors" + "fmt" + "reflect" +) + +func CheckFieldsForNil(s any) error { + var serverValue reflect.Value + if reflect.TypeOf(s).Kind() == reflect.Ptr { + serverValue = reflect.ValueOf(s).Elem() + } else { + serverValue = reflect.ValueOf(s) + } + for i := 0; i < serverValue.NumField(); i++ { + fieldValue := serverValue.Field(i) + if fieldValue.Kind() == reflect.Ptr && fieldValue.IsNil() { + return errors.New(fmt.Sprint("field ", serverValue.Type().Field(i).Name, " is nil")) + } + } + return nil +} diff --git a/internal/utils/checkFieldsForNil_test.go b/internal/utils/checkFieldsForNil_test.go new file mode 100644 index 0000000..5ee8457 --- /dev/null +++ b/internal/utils/checkFieldsForNil_test.go @@ -0,0 +1,38 @@ +package utils_test + +import ( + "github.com/onsi/ginkgo/v2" + "github.com/onsi/gomega" + "pinman/internal/utils" +) + +type TestStruct struct { + Field1 *string + Field2 *string + Field3 *string +} + +var _ = ginkgo.Describe("CheckFieldsForNil", func() { + ginkgo.When("given a struct with all fields set", func() { + ginkgo.It("should return nil", func() { + testStruct := TestStruct{ + Field1: utils.PtrString(""), + Field2: utils.PtrString(""), + Field3: utils.PtrString(""), + } + err := utils.CheckFieldsForNil(testStruct) + gomega.Expect(err).To(gomega.BeNil()) + }) + }) + ginkgo.When("given a struct with one field set", func() { + ginkgo.It("should return an error", func() { + testStruct := TestStruct{ + Field1: utils.PtrString(""), + Field2: nil, + Field3: nil, + } + err := utils.CheckFieldsForNil(testStruct) + gomega.Expect(err).NotTo(gomega.BeNil()) + }) + }) +}) diff --git a/web/app/src/api/pinballMap.test.ts b/web/app/src/api/pinballMap.test.ts new file mode 100644 index 0000000..f35c519 --- /dev/null +++ b/web/app/src/api/pinballMap.test.ts @@ -0,0 +1,62 @@ +import axios from "axios"; +import {Api} from "./pinballMap"; + +jest.mock('axios'); +const mockedAxios = axios as jest.Mocked; + +beforeEach(() => { + mockedAxios.get.mockReset() +}) + +describe('Api.getLocations()', () => { + it('returns locations if api call was successful', async () => { +const locations = [{ + id: 1, + name: 'Location 1', + street: '123 Main St', + city: 'Anytown', + state: 'CA', + zip: '12345', + country: 'USA', + num_machines: 5 + }] + mockedAxios.get.mockResolvedValueOnce({data: {locations: locations}}) + + const result = await new Api().locationsGet('Location 1') + expect(mockedAxios.get).toBeCalledTimes(1) + expect(mockedAxios.get).toBeCalledWith( + 'https://pinballmap.com/api/v1/locations.json?by_location_name=Location%201' + ) + expect(result).toEqual(locations) + }) +}) + +describe('Api.parseError()', () => { + it('returns error response if error is axios error', () => { + const errorResponse = { + errors: 'Error message' + } + const axiosError = { + isAxiosError: true, + response: { + data: errorResponse + } + } + const result = new Api().parseError(axiosError as any) + expect(result).toEqual(errorResponse) + }) + it('throws error if error is not axios error', () => { + const errorResponse = { + errors: 'Error message' + } + const axiosError = { + isAxiosError: false, + response: { + data: errorResponse + } + } + expect(() => { + new Api().parseError(axiosError as any) + }).toThrowError() + }) +})