Getting an error when testing the api endpoint of my profile view

Hello, I need some assistance. I’m getting an error message when I run an automated test on my user profile api endpoint with DRF.

Maybe I set up the test incorrectly, but I tried creating the test similarly to my login/register api tests. Also, this problem is related to the UI issue I’m currently having with the frontend VueJS api call in my HomeownerDashboard (profile page) when I register as a dummy user account and try to access or navigate to the homeowner dashboard page.

I inspected the network tab and that’s what revealed the UI error on the right side. But my main objective now, is to debug this error traceback. Here is the error

  show_sunset_warning()
System check identified no issues (0 silenced).
.E.
======================================================================
ERROR: test_profile (arborfindr.test.test_profile.HomeownerProfileTest.test_profile)
----------------------------------------------------------------------
TypeError: HomeownerProfileTest.test_profile() missing 1 required positional argument: 'user_id'

----------------------------------------------------------------------
Ran 3 tests in 1.088s

FAILED (errors=1)
Destroying test database for alias 'default'...

test_register.py

from django.urls import reverse
from rest_framework import status
from rest_framework.test import APITestCase
from ..models import User


class UserRegisterTests(APITestCase):
    def test_register_user(self):
        url = reverse('arborfindr:register')
        data = {'email': 'myemail@mail.com', 'username': 'jonedoe12', 'password': 'mypassword123'}
        response = self.client.post(url, data, format='json')
        self.assertTrue(User.objects.filter(username='jonedoe12').exists())
        user = User.objects.get(username='jonedoe12')
        self.assertEqual(user.email, 'myemail@mail.com')
        self.assertTrue(user.check_password('mypassword123'))

serializer.py

from rest_framework import serializers
from django.contrib.auth import authenticate
from .models import User, HomeownerUser
from .search_indexes import ArboristCompanyIndex, ServiceTypeIndex
from drf_haystack.serializers import HaystackSerializer


class RegisterSerializer(serializers.ModelSerializer):
    password = serializers.CharField(style={'input_type': 'password'}, write_only=True)

    class Meta:
        model = User
        fields = ['email', 'username', 'password']
        extra_kwargs = {
            'password': {'write_only': True}
        }
        
    def validate(self, valid):
        if valid['password'] != valid['password']:
            raise serializers.ValidationError({"password": "Passwords do not match."})
        return valid

    def create(self, validated_data):
        user = User.objects.create_user(
            email=validated_data['email'],
            username=validated_data['username'],
            password=validated_data['password']
        )
        return user

class LoginSerializers(serializers.ModelSerializer):
    email = serializers.CharField(max_length=255)
    password = serializers.CharField(
        label =("Password"),
        style={'input_type': 'password'},
        trim_whitespace=False,
        max_length=128,
        write_only=True
    )

    def validate(self, data):
        email = data.get('email')
        password = data.get('password')

        if email and password:
            user = authenticate(request=self.context.get('request'),
                                email=email, password=password)

            if not user:
                msg = ('Invalid email/password')
                raise serializers.ValidationError(msg, code = 'Authorization')
        else:
            msg = ('Must include valid "email" and "password".')
            raise serializers.ValidationError(msg, code = 'Authorization')

        data['user'] = user
        return data
    
    
class HomeownerProfileSerializer(serializers.ModelSerializer):
    class Meta:
        model = HomeownerUser
        fields = ['profile_pic', 'street_address', 'homeowner_city', 'homeowner_state', 'homeowner_zip_code']


class ServiceTypeSerializer(HaystackSerializer):
    class Meta:
        index_class = [ServiceTypeIndex]
        fields = ['text', 'name']


class CompanySerializer(HaystackSerializer):
 
    class Meta:
        index_class = [ArboristCompanyIndex]
        fields = [
            'text', 'company_name', 'company_city', 'company_state'
        ]

views.py

@authentication_classes([JWTAuthentication])
class LoginView(APIView):
    authentication_classes = (JWTAuthentication,)  # Keep as tuple if you prefer

    def post(self, request, *args, **kwargs):
        serializer = LoginSerializers(data=request.data, context={'request': request})
        serializer.is_valid(raise_exception=True)
        user = serializer.validated_data['user']
        login(request, user)  # Corrected: Pass the request object
        token = Token.objects.create(user=user)  # Auth Token

        if user is not None:  # This block is now reachable
            # Generate token
            refresh = RefreshToken.for_user(user)
            access_token = str(refresh.access_token)
            return Response({
                'message': 'Successful login',
                'access_token': access_token,
                'refresh_token': str(refresh),
                "Token": token.key # Added auth token
            }, status=status.HTTP_200_OK)

        return Response({'error': 'Invalid email/password'}, status=status.HTTP_401_UNAUTHORIZED)  # Now reachable


@authentication_classes([JWTAuthentication])
class RegisterView(APIView):  
    authentication_classes = (JWTAuthentication)
    def post(self, request):
        serializer = RegisterSerializer(data=request.data, context={'request': request})
        if serializer.is_valid():
            serializer.save()
            return Response({
                'message': 'successfully registered',  }, status=status.HTTP_201_CREATED)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)


@authentication_classes([JWTAuthentication])
class PasswordUpdateView(APIView):
    authentication_classes = (JWTAuthentication)
    def update_password(request):
        if request.method == 'POST':
            form = PasswordChangeForm(request.user, request.POST)
        if form.is_valid():
            user = form.save()
            update_session_auth_hash(request, user)  # To keep the user logged in
            return redirect('search_index/arborfindr/search_arborist.html')
        else:
            form = PasswordChangeForm(request.user)
        return render(request, 'registration/update_password.html', {'form': form})


@authentication_classes([JWTAuthentication])
class HomeownerProfileView(APIView):
    permission_classes = [DjangoModelPermissionsOrAnonReadOnly]
    authentication_classes = (JWTAuthentication)
    serializer_class = HomeownerProfileSerializer
    def get(self):
        username = self.kwargs['username']
        obj = get_object_or_404(User, username=username)
        return obj

    def delete(self, request, *args, **kwargs):
        return self.destroy(request, *args, **kwargs)
    
    def put(self, request, *args, **kwargs):
        return self.update(request, *args, **kwargs)
    
    
@authentication_classes([JWTAuthentication]) 
class CompanySearchView(HaystackViewSet):
    permission_classes = [DjangoModelPermissionsOrAnonReadOnly]
    authentication_classes = (JWTAuthentication)
    serializer_class = CompanySerializer
    index_classes = [ArboristCompanyIndex]
    
    def get_queryset(self):
        query = self.request.GET.get('q', '')
        queryset = SearchQuerySet().filter(text=query).facet('company_name', 'company_city', 'company_state', 'experience')
        return queryset
    
    def list(self, request, *args, **kwargs):
        queryset = self.filter_queryset(self.get_queryset())
        
        facets = queryset.facets()
        serializer = self.get_serializer(queryset, many=True)
        return Response({'search_results': serializer.data, 'facets': facets}, status=status.HTTP_200_OK)
       
        
@authentication_classes([JWTAuthentication])    
class ServicesTypeView(HaystackViewSet):
    permission_classes = [DjangoModelPermissionsOrAnonReadOnly]
    authentication_classes = (JWTAuthentication)
    serializer_class = ServiceTypeSerializer 
    index_classes = [ServiceTypeIndex]
    
    def get_queryset(self):
        query = self.request.GET.get('q', '')
        queryset = SearchQuerySet().filter(text=query)
        service_type = self.request.GET.get('service_type')
        if service_type:
            queryset = queryset.filter(name=service_type)
            facets = queryset.facets()
        return Response({'facets': facets}, status=status.HTTP_200_OK)

urls.py

from django.urls import path

from .views import services_info

from . import views

from django.contrib.auth import views as auth_views

from django.conf import settings

from django.conf.urls.static import static

from .views import RegisterView, LoginView, HomeownerProfileView, CompanySearchView, PasswordUpdateView, ServicesTypeView

from rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshView

from rest_framework import routers

router = routers.DefaultRouter()

router.register(r'company/search', CompanySearchView, basename='company-search')

router.register(r'tree/services', ServicesTypeView, basename='tree-services')

app_name = 'arborfindr'

urlpatterns = [

path('register/', RegisterView.as_view(), name='register'), # Register API endpoint url

path('login/', LoginView.as_view(), name ='login'), # Login API endpoint url

path('logout/', auth_views.LogoutView.as_view(), name='logout'),

path('update/password', PasswordUpdateView.as_view(), name='update-password'),

path('homeowner/profile/', HomeownerProfileView.as_view(), name='homeowner'),

path('token/', TokenObtainPairView.as_view(), name='token_obtain_pair'),

path('token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),

] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

So that’s all of my files. Also any suggestions on how to improve my api test/view for profile user would be great. I want to make the sure the frontend homeowner dashboard is able to retrieve data by communication with my backend profile page api endpoint properly.

Thank you. Anything else I can provide to clear this, please let me know

I checked the error again, it mentions ‘missing 1 positional argument’. I understand that I have to add this positional argument user_id somewhere in my test. So just trying to figure where to add it.

This is the code throwing the error. Where is that test? What view is it testing?

This apiview specifically

@authentication_classes([JWTAuthentication])
class HomeownerProfileView(APIView):
    permission_classes = [DjangoModelPermissionsOrAnonReadOnly]
    authentication_classes = (JWTAuthentication)
    serializer_class = HomeownerProfileSerializer
    def get(self):
        username = self.kwargs['username']
        obj = get_object_or_404(User, username=username)
        return obj

    def delete(self, request, *args, **kwargs):
        return self.destroy(request, *args, **kwargs)
    
    def put(self, request, *args, **kwargs):
        return self.update(request, *args, **kwargs)

Here is the test

from rest_framework.test import APITestCase
from ..models import User
from django.test import TestCase, Client


class HomeownerProfileTest(APITestCase):
    def test_profile(self, user_id):
        user = User.objects.create(username='test_homeowner')
        user.set_password('password321')
        user.save()
        client = Client()
        client.login(username='test_homeowner', password='password321')
        response = client.get('homeowner/profile/', self.user_id)
        self.assertEqual(response.status_code, 200)

I’m not aware of a standard method to pass parameters to a test method. At least as far as I’m aware, this isn’t a proper calling sequence for a test.

I’m also curious, you have:

and:

But:

I don’t see where this url accepts a url segment parameter.

Okay, what do you suggest I do for the homeowner profile page then? Specifically how do I go about testing this api endpoint?

I have no idea about that. I don’t use DRF and have never written a test for a DRF function. I’m simply addressing the error you reported in the original post.

Thanks anyway. Does anyone else on here know anything about testing DRF specific API’s?

The testing for the registration/login seemed pretty straightforward to me. But this is a different apiview