Open kev26 opened 2 years ago
@kev26
My approach for this is i separate my settings file inside a folder like below inside my setting file i put the setting file for production, development and test file.
To explain the above file in the.
Content of __init__.py
i read the Environment file and decide which file to load.
The base.py
contains the common setting configuration.
So here is the part where you can put your email activation class in the test.py
like below.
soon we will write the class i mentioned in the above screenshot authentications.email.ActivationEmail
Now we are done with the setting part let's move to the email activation class where i put the class inside my
authentications
app and in email.py
file but you can put it anywhere
So approach is to put all the email activations code in a dictionary at the run time and get the code from that dictionary.
FYI: this might be the dumbest approach but untill you get a workaround this might help.
let's continue
So in the authentications
app email.py
file create a class name called ActivationEmail
from django.contrib.auth.tokens import default_token_generator
# djoser imports
from templated_mail.mail import BaseEmailMessage
from djoser import utils
from djoser.conf import settings
EMAILS = {}
class ActivationEmail(BaseEmailMessage):
"""Email Activation Token Generator
"""
template_name = "email/activation.html"
def get_context_data(self):
# ActivationEmail can be deleted
context = super().get_context_data()
user = context.get("user")
context["uid"] = utils.encode_uid(user.pk)
context["token"] = default_token_generator.make_token(user)
context["url"] = settings.ACTIVATION_URL.format(**context)
uid, token = context['uid'], context['token']
EMAILS[user.email] = {'uid': uid, 'token': token}
return context
So any in the testing file you can test the user creation like this
def test_create_user(self):
"""
Test for creating users using API.
"""
url = reverse("user-list")
response = self.client.post(
url,
self.user_info,
)
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
user = User.objects.get(id=response.data['id'])
self.assertEqual(user.email, self.user_info["email"])
self.assertEqual(user.username, self.user_info["username"])
# self.assertEqual(user.ssn, self.user_info["ssn"])
self.assertTrue(user.password is not self.user_info["password"])
self.assertTrue(user.is_deleted is not True)
self.assertTrue(user.father_first_name is None)
self.assertTrue(user.mother_first_name is None)
self.assertTrue(user.password is not None)
self.assertTrue(user.birth_date is not None)
def test_get_token(self):
"""
This test is used to test the login API. getting token and testing the token.
"""
# Create a new user to login
user_info = generate_user_info()
new_user = self.client.post(
reverse("user-list"),
user_info,
)
self.assertEqual(new_user.status_code, status.HTTP_201_CREATED)
# Activation of User
from authentications.email import EMAILS
activation_url = "http://127.0.0.1:8000/auth/users/activation/"
activation_data = EMAILS[user_info["email"]]
self.client.post(activation_url, activation_data)
url = reverse("jwt-create")
data = {
"username": user_info["username"],
"password": user_info["password"],
}
response = self.client.post(url, data)
self.assertTrue(response.status_code, status.HTTP_200_OK)
self.assertTrue(response.data["access"] is not None)
hope this helps but if anyone finds a better approach i would love to see it.
Enjoy.
Actually when testing to create account (user sign-up) it does NOT send activation email so it doesn't save any uid and token in EMAIL dict in email.py file
So when does the email is sent ? @saaz181
So when does the email is sent ? @saaz181
I set up my settings like you explained but it doesn't send any email
it throws keyError on test_get_token function on:
activation_data = EMAILS[self.user_info["email"]]
so I printed out the EMAILS
dict and it was an empty dict
actually my user_info
is like:
self.user_info = {
"username": self.username,
"phone": self.phone,
"email": self.email,
"password": self.password,
"re_password": self.password,
}
Perhaps you forget to change the environment variable.
Or you can do like this if you want
ENVIROMENT=test python manage.py test
Make you sure you run on the test enviroment becausethe setting wont be able to load the test setting config. you can check by adding print value on the settings/test.py
if your print actually prints when you run the test it might be other problem.
@saaz181
I don't disable SEND_ACTIVATION_EMAIL
. Just use regex to pull uid and token out of email and do POST request.
Here's my example using pytest:
@pytest.fixture
def email_activation_url():
return reverse('user-activation')
@pytest.mark.django_db
def test_email_activation(
api_client: APIClient,
registration_url: str,
email_activation_url: str,
):
expected_user = dict(
email="tester@gmail.com",
username="tester",
password="superTester1sPass.",
)
response: Response = api_client.post(
path=registration_url,
data=expected_user,
)
assert response.status_code == status.HTTP_201_CREATED, response.data
user = UserModel.objects.filter(email=expected_user['email']).first()
assert user.is_active is False
assert len(mail.outbox) == 1
first_email = mail.outbox[0]
# Check that we received activation email
activation_email_re = re.compile(
r'.*Please go to the following page to activate account:.*',
re.I + re.M,
)
activation_re_result = activation_email_re.search(first_email.body)
assert activation_re_result is not None
# regex template is based on string '#/activate/{uid}/{token}'. Check Djoser Settings
activation_url_template = r'/activate/(?P<uid>.*)/(?P<token>.*)[\"\n>]'
activation_url_re = re.search(
activation_url_template,
first_email.body,
re.U + re.I + re.M,
)
assert activation_url_re is not None
uid = activation_url_re.groupdict().get('uid')
assert uid is not None
token = activation_url_re.groupdict().get('token')
assert token is not None
response = api_client.post(
path=email_activation_url,
data={
'uid': uid,
'token': token
}
)
assert response.status_code == status.HTTP_204_NO_CONTENT, response.data
user.refresh_from_db()
assert user.is_active is True
My registeration follow : register --> get uid & token via email --> use ui & token for activation --> login--> accsess_token.
So if easily if I disable the feature SEND_ACTIVATION_EMAIL, but if I want to write a test with this feature, how to do it? And this is necessary for the test?