From 873bd1539fd1add0eb68e5e7958e61de56232a4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Puerta=20Mart=C3=ADn?= Date: Sat, 20 Apr 2024 04:18:28 -0400 Subject: [PATCH] Add unit tests for project functionality --- README.md | 30 +++ ninjemail/tests/__init__.py | 0 ninjemail/tests/test_email_gmail.py | 167 ++++++++++++++ ninjemail/tests/test_email_outlook.py | 129 +++++++++++ ninjemail/tests/test_email_yahoo.py | 154 +++++++++++++ ninjemail/tests/test_manager.py | 294 ++++++++++++++++++++++++ ninjemail/tests/test_sms_getsmscode.py | 95 ++++++++ ninjemail/tests/test_sms_smspool.py | 94 ++++++++ ninjemail/tests/test_utils.py | 70 ++++++ ninjemail/tests/test_webdriver_utils.py | 79 +++++++ requirements.txt | 3 + 11 files changed, 1115 insertions(+) create mode 100644 ninjemail/tests/__init__.py create mode 100644 ninjemail/tests/test_email_gmail.py create mode 100644 ninjemail/tests/test_email_outlook.py create mode 100644 ninjemail/tests/test_email_yahoo.py create mode 100644 ninjemail/tests/test_manager.py create mode 100644 ninjemail/tests/test_sms_getsmscode.py create mode 100644 ninjemail/tests/test_sms_smspool.py create mode 100644 ninjemail/tests/test_utils.py create mode 100644 ninjemail/tests/test_webdriver_utils.py diff --git a/README.md b/README.md index 23b0859..6f5ac4c 100644 --- a/README.md +++ b/README.md @@ -53,6 +53,36 @@ To install Ninjemail, you can follow these steps: You can then proceed to use Ninjemail as described in the next instructions. +## Testing + +To ensure the reliability and correctness of this project, tests have been implemented using [pytest](https://pytest.org/). The test suite covers various aspects of the codebase and helps maintain the desired functionality as the project evolves. + +### Running Tests + +1. Make sure you have the project's dependencies installed. + +2. Navigate to the project's root directory. + +3. Run the following command to execute the test suite: + + ```bash + pytest + ``` + +### Test Coverage + +Comprehensive test coverage is prioritized to minimize bugs and regressions. The current code coverage can be measured using pytest-cov. To generate a coverage report, users can execute the following command: + +```bash +pytest --cov +``` + +The coverage report will be displayed in the terminal. + +### Writing Tests + +When adding new features or fixing bugs, it's important to include corresponding test cases to validate the changes. Tests should be placed in the `tests/` directory, following a naming convention such as `test_module.py` or `test_class.py`. You can organize the tests based on the project's structure. + ## Usage ### Importing the Library diff --git a/ninjemail/tests/__init__.py b/ninjemail/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/ninjemail/tests/test_email_gmail.py b/ninjemail/tests/test_email_gmail.py new file mode 100644 index 0000000..e2bdf41 --- /dev/null +++ b/ninjemail/tests/test_email_gmail.py @@ -0,0 +1,167 @@ +import pytest +from unittest.mock import Mock, MagicMock +from selenium.webdriver.common.keys import Keys +from ..email_providers.gmail import create_account +from ..utils.webdriver_utils import create_driver + +@pytest.fixture(autouse=True) +def mock_gmail(monkeypatch): + # Mock GeckoDriverManager and ChromeDriverManager installations + monkeypatch.setattr('webdriver_manager.firefox.GeckoDriverManager.install', lambda *args, **kwargs: 'gecko_driver_path') + monkeypatch.setattr('webdriver_manager.chrome.ChromeDriverManager.install', lambda *args, **kwargs: 'chrome_driver_path') + + # Mock WebDriver classes + mock_firefox = Mock() + mock_chrome = Mock() + monkeypatch.setattr('selenium.webdriver.Firefox', lambda *args, **kwargs: mock_firefox) + monkeypatch.setattr('selenium.webdriver.Chrome', lambda *args, **kwargs: mock_chrome) + + # Mock WebDriver methods + mock_firefox.get = MagicMock() + mock_chrome.get = MagicMock() + mock_firefox.find_element = MagicMock(return_value=Mock()) + mock_chrome.find_element = MagicMock(return_value=Mock()) + mock_firefox.find_elements = MagicMock(return_value=[Mock()]) + mock_chrome.find_elements = MagicMock(return_value=[Mock()]) + mock_firefox.quit = MagicMock() + mock_chrome.quit = MagicMock() + + # Mock WebDriverWait and expected_conditions + mock_wait = MagicMock() + monkeypatch.setattr('selenium.webdriver.support.ui.WebDriverWait', lambda *args, **kwargs: mock_wait) + mock_wait.until = MagicMock(return_value=Mock()) + monkeypatch.setattr('selenium.webdriver.support.expected_conditions.presence_of_element_located', lambda *args, **kwargs: MagicMock()) + monkeypatch.setattr('selenium.webdriver.support.expected_conditions.element_to_be_clickable', lambda *args, **kwargs: MagicMock()) + + # Correctly mock Select class + def mock_select_init(self, *args, **kwargs): + self.select_by_index = MagicMock() + self.select_by_visible_text = MagicMock() + self.select_by_value = MagicMock() + + monkeypatch.setattr('selenium.webdriver.support.ui.Select.__init__', mock_select_init) + + # Mock Keys + monkeypatch.setattr('selenium.webdriver.common.keys.Keys', Keys) + + # Mock time + monkeypatch.setattr('time.sleep', MagicMock(())) + + # Mock logging + monkeypatch.setattr('logging.info', MagicMock()) + monkeypatch.setattr('logging.error', MagicMock()) + +# Mock sms services +def mock_get_phone_getsmscode(self, *args, **kwargs): + return '111111111' + +def mock_get_phone_smspool(self, *args, **kwargs): + return 'ordeid', '111111111' + +def mock_get_code(self, *arg, **kwargs): + return '000000' + +def mock_get_phone_fail(self, *args, **kwargs): + raise Exception("Failed to get phone number") + +def mock_get_code_fail(self, *args, **kwargs): + raise Exception("Failed to retreive code") + +def test_create_account_firefox_and_getsmscode(monkeypatch): + monkeypatch.setattr('sms_services.getsmscode.GetsmsCode.get_phone', mock_get_phone_getsmscode) + monkeypatch.setattr('sms_services.getsmscode.GetsmsCode.get_code', mock_get_code) + + driver = create_driver('firefox') + # Test data + sms_key = { + "name": "getsmscode", + "data": { + "user": "username", + "token": "your_api_key", + } + } + username = "testuser" + password = "testpassword" + first_name = "John" + last_name = "Doe" + month = "1" + day = "1" + year = "2000" + + email, password = create_account(driver, sms_key, username, password, first_name, last_name, month, day, year) + assert email == f"{username}@gmail.com" + assert password == "testpassword" + +def test_create_account_chrome_and_smspool(monkeypatch): + monkeypatch.setattr('sms_services.smspool.SMSPool.get_phone', mock_get_phone_smspool) + monkeypatch.setattr('sms_services.smspool.SMSPool.get_code', mock_get_code) + + driver = create_driver('chrome') + # Test data + sms_key = { + "name": "smspool", + "data": { + "token": "your_api_key", + } + } + username = "testuser" + password = "testpassword" + first_name = "John" + last_name = "Doe" + month = "1" + day = "1" + year = "2000" + + email, password = create_account(driver, sms_key, username, password, first_name, last_name, month, day, year) + assert email == f"{username}@gmail.com" + assert password == "testpassword" + +def test_create_account_phone_fail(monkeypatch): + monkeypatch.setattr('sms_services.getsmscode.GetsmsCode.get_phone', mock_get_phone_fail) + + driver = create_driver('firefox') + # Test data + sms_key = { + "name": "getsmscode", + "data": { + "user": "username", + "token": "your_api_key", + } + } + username = "testuser" + password = "testpassword" + first_name = "John" + last_name = "Doe" + month = "1" + day = "1" + year = "2000" + + with pytest.raises(Exception, match="Failed to get phone number"): + email, password = create_account(driver, sms_key, username, password, first_name, last_name, month, day, year) + assert email == None + assert password == None + +def test_create_account_code_fail(monkeypatch): + monkeypatch.setattr('sms_services.smspool.SMSPool.get_phone', mock_get_phone_smspool) + monkeypatch.setattr('sms_services.smspool.SMSPool.get_code', mock_get_code_fail) + + driver = create_driver('firefox') + # Test data + sms_key = { + "name": "smspool", + "data": { + "token": "your_api_key", + } + } + username = "testuser" + password = "testpassword" + first_name = "John" + last_name = "Doe" + month = "1" + day = "1" + year = "2000" + + with pytest.raises(Exception, match="Failed to retreive code"): + email, password = create_account(driver, sms_key, username, password, first_name, last_name, month, day, year) + assert email == None + assert password == None diff --git a/ninjemail/tests/test_email_outlook.py b/ninjemail/tests/test_email_outlook.py new file mode 100644 index 0000000..2ddd542 --- /dev/null +++ b/ninjemail/tests/test_email_outlook.py @@ -0,0 +1,129 @@ +import pytest +from unittest.mock import Mock, MagicMock +from selenium.webdriver.common.keys import Keys +from ..email_providers.outlook import create_account +from ..utils.webdriver_utils import create_driver + +@pytest.fixture(autouse=True) +def mock_outlook(monkeypatch): + # Mock GeckoDriverManager and ChromeDriverManager installations + monkeypatch.setattr('webdriver_manager.firefox.GeckoDriverManager.install', lambda *args, **kwargs: 'gecko_driver_path') + monkeypatch.setattr('webdriver_manager.chrome.ChromeDriverManager.install', lambda *args, **kwargs: 'chrome_driver_path') + + # Mock WebDriver classes + mock_firefox = Mock() + mock_chrome = Mock() + monkeypatch.setattr('selenium.webdriver.Firefox', lambda *args, **kwargs: mock_firefox) + monkeypatch.setattr('selenium.webdriver.Chrome', lambda *args, **kwargs: mock_chrome) + + # Mock WebDriver methods + mock_firefox.get = MagicMock() + mock_chrome.get = MagicMock() + mock_firefox.find_element = MagicMock(return_value=Mock()) + mock_chrome.find_element = MagicMock(return_value=Mock()) + mock_firefox.find_elements = MagicMock(return_value=[Mock()]) + mock_chrome.find_elements = MagicMock(return_value=[Mock()]) + mock_firefox.quit = MagicMock() + mock_chrome.quit = MagicMock() + + # Mock WebDriverWait and expected_conditions + mock_wait = MagicMock() + monkeypatch.setattr('selenium.webdriver.support.ui.WebDriverWait', lambda *args, **kwargs: mock_wait) + mock_wait.until = MagicMock(return_value=Mock()) + monkeypatch.setattr('selenium.webdriver.support.expected_conditions.presence_of_element_located', lambda *args, **kwargs: MagicMock()) + monkeypatch.setattr('selenium.webdriver.support.expected_conditions.element_to_be_clickable', lambda *args, **kwargs: MagicMock()) + monkeypatch.setattr('selenium.webdriver.support.expected_conditions.visibility_of_element_located', lambda *args, **kwargs: MagicMock()) + monkeypatch.setattr('selenium.webdriver.support.expected_conditions.frame_to_be_available_and_switch_to_it', lambda *args, **kwargs: MagicMock()) + + # Correctly mock Select class + def mock_select_init(self, *args, **kwargs): + self.select_by_index = MagicMock() + self.select_by_visible_text = MagicMock() + self.select_by_value = MagicMock() + + monkeypatch.setattr('selenium.webdriver.support.ui.Select.__init__', mock_select_init) + + # Mock Keys + monkeypatch.setattr('selenium.webdriver.common.keys.Keys', Keys) + + # Mock time + monkeypatch.setattr('time.sleep', MagicMock(())) + + # Mock logging + monkeypatch.setattr('logging.info', MagicMock()) + monkeypatch.setattr('logging.error', MagicMock()) + +# Mock sms services +def mock_get_phone_getsmscode(self, *args, **kwargs): + return '111111111' + +def mock_get_phone_smspool(self, *args, **kwargs): + return 'ordeid', '111111111' + +def mock_get_code(self, *arg, **kwargs): + return '000000' + +def mock_get_phone_fail(self, *args, **kwargs): + raise Exception("Failed to get phone number") + +def mock_get_code_fail(self, *args, **kwargs): + raise Exception("Failed to retreive code") + +def test_create_account_firefox(): + + driver = create_driver('firefox') + # Test data + captcha_key= "4564654777" + username = "testuser" + password = "testpassword" + first_name = "John" + last_name = "Doe" + country = "us" + month = "1" + day = "1" + year = "2000" + hotmail = False + + email, password = create_account(captcha_key, driver, username, password, first_name, last_name, country, month, day, year, hotmail) + assert email == f"{username}@outlook.com" + assert password == "testpassword" + +def test_create_account_chrome(): + + driver = create_driver('chrome') + # Test data + captcha_key="5456646656" + username = "testuser" + password = "testpassword" + first_name = "John" + last_name = "Doe" + country="us" + month = "1" + day = "1" + year = "2000" + hotmail = False + + email, password = create_account(captcha_key, driver, username, password, first_name, last_name, country, month, day, year, hotmail) + assert email == f"{username}@outlook.com" + assert password == "testpassword" + +def test_create_hotmail_account(): + + driver = create_driver('chrome') + # Test data + + captcha_key="5456646656" + username = "testuser" + password = "testpassword" + first_name = "John" + last_name = "Doe" + country = "us" + month = "1" + day = "1" + year = "2000" + hotmail = True + + email, password = create_account(captcha_key, driver, username, password, first_name, last_name, country, month, day, year, hotmail) + assert email == f"{username}@hotmail.com" + assert password == "testpassword" + diff --git a/ninjemail/tests/test_email_yahoo.py b/ninjemail/tests/test_email_yahoo.py new file mode 100644 index 0000000..459ad3c --- /dev/null +++ b/ninjemail/tests/test_email_yahoo.py @@ -0,0 +1,154 @@ +import pytest +from unittest.mock import Mock, MagicMock +from selenium.webdriver.common.keys import Keys +from ..email_providers.yahoo import create_account +from ..utils.webdriver_utils import create_driver + +@pytest.fixture(autouse=True) +def mock_yahoo(monkeypatch): + # Mock GeckoDriverManager and ChromeDriverManager installations + monkeypatch.setattr('webdriver_manager.firefox.GeckoDriverManager.install', lambda *args, **kwargs: 'gecko_driver_path') + monkeypatch.setattr('webdriver_manager.chrome.ChromeDriverManager.install', lambda *args, **kwargs: 'chrome_driver_path') + + # Mock WebDriver classes + mock_firefox = Mock() + mock_chrome = Mock() + monkeypatch.setattr('selenium.webdriver.Firefox', lambda *args, **kwargs: mock_firefox) + monkeypatch.setattr('selenium.webdriver.Chrome', lambda *args, **kwargs: mock_chrome) + + # Mock WebDriver methods + mock_firefox.get = MagicMock() + mock_chrome.get = MagicMock() + mock_firefox.current_url = '/create/success' + mock_chrome.current_url = '/create/success' + mock_firefox.find_element = MagicMock(return_value=Mock()) + mock_chrome.find_element = MagicMock(return_value=Mock()) + mock_firefox.find_elements = MagicMock(return_value=[Mock()]) + mock_chrome.find_elements = MagicMock(return_value=[Mock()]) + mock_firefox.quit = MagicMock() + mock_chrome.quit = MagicMock() + + # Mock WebDriverWait and expected_conditions + mock_wait = MagicMock() + monkeypatch.setattr('selenium.webdriver.support.ui.WebDriverWait', lambda *args, **kwargs: mock_wait) + mock_wait.until = MagicMock(return_value=Mock()) + monkeypatch.setattr('selenium.webdriver.support.expected_conditions.presence_of_element_located', lambda *args, **kwargs: MagicMock()) + monkeypatch.setattr('selenium.webdriver.support.expected_conditions.element_to_be_clickable', lambda *args, **kwargs: MagicMock()) + monkeypatch.setattr('selenium.webdriver.support.expected_conditions.visibility_of_element_located', lambda *args, **kwargs: MagicMock()) + monkeypatch.setattr('selenium.webdriver.support.expected_conditions.frame_to_be_available_and_switch_to_it', lambda *args, **kwargs: MagicMock()) + + # Correctly mock Select class + def mock_select_init(self, *args, **kwargs): + self.select_by_index = MagicMock() + self.select_by_visible_text = MagicMock() + self.select_by_value = MagicMock() + + monkeypatch.setattr('selenium.webdriver.support.ui.Select.__init__', mock_select_init) + + # Mock Keys + monkeypatch.setattr('selenium.webdriver.common.keys.Keys', Keys) + + # Mock time + monkeypatch.setattr('time.sleep', MagicMock(())) + + # Mock logging + monkeypatch.setattr('logging.info', MagicMock()) + monkeypatch.setattr('logging.error', MagicMock()) + +# Mock sms services +def mock_get_phone_getsmscode(self, *args, **kwargs): + return '111111111' + +def mock_get_phone_smspool(self, *args, **kwargs): + return 'ordeid', '111111111' + +def mock_get_code(self, *arg, **kwargs): + return '000000' + +def mock_get_phone_fail(self, *args, **kwargs): + raise Exception("Failed to get phone number") + +def mock_get_code_fail(self, *args, **kwargs): + raise Exception("Failed to retreive code") + +def test_create_account_firefox_and_getsmscode(monkeypatch): + monkeypatch.setattr('sms_services.getsmscode.GetsmsCode.get_phone', mock_get_phone_getsmscode) + monkeypatch.setattr('sms_services.getsmscode.GetsmsCode.get_code', mock_get_code) + + driver = create_driver('firefox') + # Test data + captcha_key= "4564654777" + sms_key = { + "name": "getsmscode", + "data": { + "user": "username", + "token": "your_api_key", + } + } + username = "testuser" + password = "testpassword" + first_name = "John" + last_name = "Doe" + month = "1" + day = "1" + year = "2000" + myyahoo = False + + email, password = create_account(captcha_key, driver, sms_key, username, password, first_name, last_name, month, day, year, myyahoo) + assert email == f"{username}@yahoo.com" + assert password == "testpassword" + +def test_create_account_chrome_and_smspool(monkeypatch): + monkeypatch.setattr('sms_services.smspool.SMSPool.get_phone', mock_get_phone_smspool) + monkeypatch.setattr('sms_services.smspool.SMSPool.get_code', mock_get_code) + + driver = create_driver('chrome') + # Test data + sms_key = { + "name": "smspool", + "data": { + "token": "your_api_key", + } + } + captcha_key="5456646656" + username = "testuser" + password = "testpassword" + first_name = "John" + last_name = "Doe" + month = "1" + day = "1" + year = "2000" + myyahoo = False + + email, password = create_account(captcha_key, driver, sms_key, username, password, first_name, last_name, month, day, year, myyahoo) + assert email == f"{username}@yahoo.com" + assert password == "testpassword" + +def test_create_myyahoo_account(monkeypatch): + monkeypatch.setattr('sms_services.smspool.SMSPool.get_phone', mock_get_phone_smspool) + monkeypatch.setattr('sms_services.smspool.SMSPool.get_code', mock_get_code) + + driver = create_driver('chrome') + # Test data + + captcha_key="5456646656" + sms_key = { + "name": "smspool", + "data": { + "token": "your_api_key", + } + } + username = "testuser" + password = "testpassword" + first_name = "John" + last_name = "Doe" + month = "1" + day = "1" + year = "2000" + myyahoo = True + + email, password = create_account(captcha_key, driver, sms_key, username, password, first_name, last_name, month, day, year, myyahoo) + assert email == f"{username}@myyahoo.com" + assert password == "testpassword" + + diff --git a/ninjemail/tests/test_manager.py b/ninjemail/tests/test_manager.py new file mode 100644 index 0000000..f5183f4 --- /dev/null +++ b/ninjemail/tests/test_manager.py @@ -0,0 +1,294 @@ +import ninjemail +import pytest +from unittest.mock import MagicMock, patch +from unittest import mock + +from ..ninjemail_manager import Ninjemail +from ..email_providers import outlook +from fp.errors import FreeProxyException + + + +def test_init_valid_browser(): + """Tests Ninjemail initialization with a valid browser.""" + manager = Ninjemail() + assert manager.browser == "firefox" + + +def test_init_invalid_browser(): + """Tests Ninjemail initialization with an invalid browser.""" + with pytest.raises(ValueError) as excinfo: + Ninjemail(browser="invalid_browser") + assert "Unsupported browser" in str(excinfo.value) + + +@patch('ninjemail_manager.FreeProxy.get') # Patching FreeProxy.get for mocking +def test_get_proxy_with_provided_proxy(mocker): + """Tests get_proxy with a user-provided proxy.""" + proxy = "http://myproxy:8080" + manager = Ninjemail(proxy=proxy) + assert manager.get_proxy() == proxy + mocker.assert_not_called() # Assert FreeProxy.get wasn't called + + +@patch('ninjemail_manager.FreeProxy.get') # Patching FreeProxy.get for mocking +def test_get_proxy_with_auto_proxy_success(mocker): + """Tests get_proxy with auto_proxy and successful free proxy retrieval.""" + manager = Ninjemail(auto_proxy=True) + mock_proxy = {"http": "http://freeproxy:3128"} + mocker.return_value = mock_proxy + assert manager.get_proxy() == mock_proxy + + +@patch('ninjemail_manager.FreeProxy.get') # Patching FreeProxy.get for mocking +def test_get_proxy_with_auto_proxy_failure(mocker): + """Tests get_proxy with auto_proxy and free proxy retrieval failure.""" + manager = Ninjemail(auto_proxy=True) + mocker.side_effect = FreeProxyException("No free proxies available") + assert manager.get_proxy() is None + + +def test_get_captcha_key_valid_provider(mocker): + """Tests get_captcha_key with a valid email provider and key.""" + mocker.patch.dict('ninjemail_manager.SUPPORTED_SOLVERS_BY_EMAIL', {'outlook': ['solver1']}) + manager = Ninjemail(captcha_keys={"solver1": "key"}) + assert manager.get_captcha_key('outlook') == "key" + + +def test_get_captcha_key_invalid_provider(): + """Tests get_captcha_key with an invalid email provider (won't pass).""" + manager = Ninjemail() + with pytest.raises(KeyError): # Expecting KeyError here + manager.get_captcha_key('invalid_provider') + + +def test_get_captcha_key_no_key_for_provider(mocker): + """Tests get_captcha_key with a valid provider but no key.""" + mocker.patch.dict('ninjemail_manager.SUPPORTED_SOLVERS_BY_EMAIL', {'outlook': ['solver1']}) + manager = Ninjemail() + with pytest.raises(ValueError) as excinfo: + manager.get_captcha_key('outlook') + assert "No captcha key provided for email provider: outlook" in str(excinfo.value) + + +def test_get_sms_key_with_keys(mocker): + """Tests get_sms_key with multiple SMS keys provided.""" + manager = Ninjemail(sms_keys={"service1": "key1", "service2": "key2"}) + selected_service = manager.get_sms_key() + assert selected_service["name"] in ["service1", "service2"] + + +def test_get_sms_key_no_keys(): + """Tests get_sms_key with no SMS keys provided.""" + manager = Ninjemail() + with pytest.raises(ValueError) as excinfo: + manager.get_sms_key() + # Check both type and message + assert isinstance(excinfo.value, ValueError) + assert str(excinfo.value) == "No SMS API keys provided for SMS verification." + + +@pytest.fixture(autouse=True) +def mock_create_account_methods(monkeypatch): + def mock_outlook(*args, **kwargs): + return "outlook_username", "outlook_password" + + def mock_gmail(*args, **kwargs): + return "gmail_username", "gmail_password" + + def mock_yahoo(*args, **kwargs): + return "yahoo_username", "yahoo_password" + + monkeypatch.setattr('email_providers.outlook.create_account', mock_outlook) + monkeypatch.setattr('email_providers.gmail.create_account', mock_gmail) + monkeypatch.setattr('email_providers.yahoo.create_account', mock_yahoo) + + def mock_gecko_install(*args, **kwargs): + return 'gecko_driver_path' + + def mock_chrome_install(*args, **kwargs): + return 'chrome_driver_path' + + def mock_firefox_service(*args, **kwargs): + return None + + def mock_chrome_service(*args, **kwargs): + return None + + def mock_firefox(*args, **kwargs): + pass + + def mock_chrome(*args, **kwargs): + pass + + def mock_firefox_quit(self): + pass + + def mock_chrome_quit(self): + pass + + monkeypatch.setattr('webdriver_manager.firefox.GeckoDriverManager.install', mock_gecko_install) + monkeypatch.setattr('webdriver_manager.chrome.ChromeDriverManager.install', mock_chrome_install) + monkeypatch.setattr('selenium.webdriver.firefox.service.Service.__init__', mock_firefox_service) + monkeypatch.setattr('selenium.webdriver.chrome.service.Service.__init__', mock_chrome_service) + monkeypatch.setattr('selenium.webdriver.Firefox.__init__', mock_firefox) + monkeypatch.setattr('selenium.webdriver.Chrome.__init__', mock_chrome) + monkeypatch.setattr('selenium.webdriver.Firefox.quit', mock_firefox_quit) + monkeypatch.setattr('selenium.webdriver.Chrome.quit', mock_chrome_quit) + +def test_create_outlook_account(): + + manager = Ninjemail(captcha_keys={'capsolver': {'token': 'aaaaaaaa'}}) + username, password = manager.create_outlook_account( + username="testuser", + password="testpassword", + first_name="Test", + last_name="User", + country="US", + birthdate="01-01-2000" + ) + + assert username == "outlook_username" + assert password == "outlook_password" + +def test_create_outlook_account_no_info(): + + manager = Ninjemail(captcha_keys={'capsolver': {'token': 'aaaaaaaa'}}) + username, password = manager.create_outlook_account( + ) + + assert username == "outlook_username" + assert password == "outlook_password" + +def test_create_outlook_account_with_proxy(): + + manager = Ninjemail(captcha_keys={'capsolver': {'token': 'aaaaaaaa'}}, proxy='http://127.0.0.1:8080') + username, password = manager.create_outlook_account( + ) + + assert username == "outlook_username" + assert password == "outlook_password" + +def test_create_outlook_account_no_captcha_key(): + + manager = Ninjemail() + with pytest.raises(ValueError) as excinfo: + manager.create_outlook_account( + username="testuser", + password="testpassword", + first_name="Test", + last_name="User", + country="US", + birthdate="01-01-2000" + ) + assert isinstance(excinfo.value, ValueError) + assert str(excinfo.value) == "No captcha key provided for email provider: outlook" + +def test_create_gmail_account(): + + manager = Ninjemail(sms_keys={'smspool': {'token': 'aaaaaaaa'}}) + username, password = manager.create_gmail_account( + username="testuser", + password="testpassword", + first_name="Test", + last_name="User", + birthdate="01-01-2000" + ) + + assert username == "gmail_username" + assert password == "gmail_password" + +def test_create_gmail_account_no_info(): + + manager = Ninjemail(sms_keys={'smspool': {'token': 'aaaaaaaa'}}) + username, password = manager.create_gmail_account( + ) + + assert username == "gmail_username" + assert password == "gmail_password" + +def test_create_gmail_account_with_proxy(): + + manager = Ninjemail(sms_keys={'smspool': {'token': 'aaaaaaaa'}}, proxy='http://127.0.0.1:8080') + username, password = manager.create_gmail_account( + ) + + assert username == "gmail_username" + assert password == "gmail_password" + +def test_create_gmail_account_no_sms_key(): + + manager = Ninjemail() + with pytest.raises(ValueError) as excinfo: + manager.create_gmail_account( + username="testuser", + password="testpassword", + first_name="Test", + last_name="User", + birthdate="01-01-2000" + ) + assert isinstance(excinfo.value, ValueError) + assert str(excinfo.value) == "No SMS API keys provided for SMS verification." + +def test_create_yahoo_account(): + + manager = Ninjemail(captcha_keys={'capsolver': {'token': 'aaaaaaaa'}}, + sms_keys={'smspool': {'token': 'bbbbbb'}}) + username, password = manager.create_yahoo_account( + username="testuser", + password="testpassword", + first_name="Test", + last_name="User", + birthdate="01-01-2000" + ) + + assert username == "yahoo_username" + assert password == "yahoo_password" + +def test_create_yahoo_account_no_info(): + + manager = Ninjemail(captcha_keys={'capsolver': {'token': 'aaaaaaaa'}}, + sms_keys={'smspool': {'token': 'bbbbbb'}}) + username, password = manager.create_yahoo_account( + ) + + assert username == "yahoo_username" + assert password == "yahoo_password" + +def test_create_yahoo_account_with_proxy(): + + manager = Ninjemail(captcha_keys={'capsolver': {'token': 'aaaaaaaa'}}, + sms_keys={'smspool': {'token': 'bbbbbb'}}, proxy='http://127.0.0.1:8080') + username, password = manager.create_yahoo_account( + ) + + assert username == "yahoo_username" + assert password == "yahoo_password" + +def test_create_yahoo_account_no_captcha_key(): + + manager = Ninjemail(sms_keys={'smspool': {'token': 'bbbbbb'}}) + with pytest.raises(ValueError) as excinfo: + manager.create_yahoo_account( + username="testuser", + password="testpassword", + first_name="Test", + last_name="User", + birthdate="01-01-2000" + ) + assert isinstance(excinfo.value, ValueError) + assert str(excinfo.value) == "No captcha key provided for email provider: yahoo" + +def test_create_yahoo_account_no_sms_key(): + + manager = Ninjemail(captcha_keys={'capsolver': {'token': 'aaaaaaaa'}}) + with pytest.raises(ValueError) as excinfo: + manager.create_yahoo_account( + username="testuser", + password="testpassword", + first_name="Test", + last_name="User", + birthdate="01-01-2000" + ) + assert isinstance(excinfo.value, ValueError) + assert str(excinfo.value) == "No SMS API keys provided for SMS verification." diff --git a/ninjemail/tests/test_sms_getsmscode.py b/ninjemail/tests/test_sms_getsmscode.py new file mode 100644 index 0000000..4a17c32 --- /dev/null +++ b/ninjemail/tests/test_sms_getsmscode.py @@ -0,0 +1,95 @@ +import re +import pytest +from unittest.mock import MagicMock, patch +import requests +from ..sms_services.getsmscode import GetsmsCode, APIError + +# Mocking requests.post +@pytest.fixture +def mock_requests_post(mocker): + mock = mocker.patch("requests.post") + mock.return_value.raise_for_status.return_value = None + mock.return_value.text = "Success" + return mock + +# Mocking time.sleep +@pytest.fixture +def mock_time_sleep(mocker): + return mocker.patch("time.sleep") + +# Fixture to create an instance of GetsmsCode +@pytest.fixture +def gs(): + return GetsmsCode(project="123", user="user", token="token", country="us") + +def test_initialization(gs): + assert gs.user == "user" + assert gs.token == "token" + assert gs.project == "123" + assert gs.country == "us" + assert gs.prefix == "1" + assert gs.API_URL == "http://api.getsmscode.com/usdo.php" + +def test_generate_generic(gs): + phone = gs._generate_generic() + assert phone.startswith("52") + assert len(phone) == 8 + +def test_get_endpoint(gs): + assert gs.get_endpoint("us") == "usdo" + assert gs.get_endpoint("hk") == "vndo" + assert gs.get_endpoint("cn") == "do" + +@patch("requests.post") +def test_request(mock_post, gs): + mock_post.return_value.raise_for_status.return_value = None + mock_post.return_value.text = "Success" + response = gs.request(action="getmobile") + assert response == "Success" + +@patch("requests.post") +def test_get_phone(mock_post, gs): + mock_post.return_value.raise_for_status.return_value = None + mock_post.return_value.text = "234567" + phone = gs.get_phone() + assert phone == "234567" + +@patch("requests.post") +def test_get_phone_with_prefix(mock_post, gs): + mock_post.return_value.raise_for_status.return_value = None + mock_post.return_value.text = "1234567" + phone = gs.get_phone(send_prefix=True) + assert phone == "1234567" + +@patch("requests.post") +def test_get_code(mock_post, gs): + mock_post.return_value.raise_for_status.return_value = None + mock_post.return_value.text = "Success|12345" + code = gs.get_code("1234567") + assert code == "12345" + +@patch("requests.post") +def test_request_failure(mock_post, gs): + mock_post.side_effect = requests.exceptions.RequestException("Network error") + with pytest.raises(requests.exceptions.RequestException): + gs.request(action="getmobile") + +@patch("requests.post") +def test_api_error_response_message(mock_post, gs): + mock_post.return_value.raise_for_status.side_effect = requests.exceptions.HTTPError() + mock_post.return_value.text = "Error|Invalid request" + with pytest.raises(requests.exceptions.HTTPError) as exc_info: + gs.request(action="getmobile") + assert str(exc_info.value) == "" + +@patch("requests.post") +def test_no_code_found(mock_post, gs): + mock_post.return_value.text = "Success|" + with pytest.raises(AssertionError): + gs.get_code("1234567") + +@patch("requests.post") +def test_request_timeout(mock_post, gs): + mock_post.side_effect = requests.exceptions.Timeout() + with pytest.raises(requests.exceptions.Timeout): + gs.request(action="getmobile") diff --git a/ninjemail/tests/test_sms_smspool.py b/ninjemail/tests/test_sms_smspool.py new file mode 100644 index 0000000..664e9e2 --- /dev/null +++ b/ninjemail/tests/test_sms_smspool.py @@ -0,0 +1,94 @@ +import pytest +import requests +from unittest.mock import MagicMock, patch + +from ..sms_services.smspool import SMSPool, APIError + +# Mocking requests.post +@pytest.fixture +def mock_requests_post(mocker): + mock = mocker.patch("requests.post") + mock.return_value.raise_for_status.return_value = None + mock.return_value.json.return_value = {"success": True} + return mock + +# Mocking time.sleep +@pytest.fixture +def mock_time_sleep(mocker): + return mocker.patch("time.sleep") + +# Fixture to create an instance of SMSPool +@pytest.fixture +def sms_pool(): + return SMSPool(service="service_id", token="api_key", country="hk") + +def test_request_success(mock_requests_post, sms_pool): + response = sms_pool.request("some_command") + assert response == {"success": True} + mock_requests_post.assert_called_once_with( + "http://api.smspool.net/some_command", + params={"key": "api_key"} + ) + +def test_request_failure(mock_requests_post, sms_pool): + mock_requests_post.return_value.raise_for_status.side_effect = requests.exceptions.HTTPError + with pytest.raises(requests.exceptions.HTTPError): + sms_pool.request("some_command") + +def test_get_phone(mock_requests_post, sms_pool): + mock_requests_post.return_value.json.return_value = { + "success": True, + "number": "1234567890", + "phonenumber": "234567890", + "order_id": "order123" + } + phone, order_id = sms_pool.get_phone() + assert phone == "234567890" + assert order_id == "order123" + +def test_get_code(mock_requests_post, sms_pool): + mock_requests_post.return_value.json.return_value = { + "success": True, + "sms": "12345" + } + code = sms_pool.get_code("order123") + assert code == "12345" + +def test_get_phone_with_prefix(mock_requests_post, sms_pool): + mock_requests_post.return_value.json.return_value = { + "success": True, + "number": "1234567890", + "phonenumber": "234567890", + "order_id": "order123" + } + phone, order_id = sms_pool.get_phone(send_prefix=True) + assert phone == "1234567890" + assert order_id == "order123" + +def test_request_error_response(mock_requests_post, sms_pool): + mock_requests_post.return_value.json.return_value = { + "success": False, + "message": "Error message" + } + with pytest.raises(APIError) as exc_info: + sms_pool.request("some_command") + assert str(exc_info.value) == "Error message" + +def test_get_phone_error_response(mock_requests_post, sms_pool): + mock_requests_post.return_value.json.return_value = { + "success": False, + "message": "Error message" + } + with pytest.raises(APIError) as exc_info: + sms_pool.get_phone() + assert str(exc_info.value) == "Error message" + +def test_get_code_error_response(mock_requests_post, mock_time_sleep, sms_pool): + mock_time_sleep.side_effect = Exception("Test exception") + mock_requests_post.return_value.json.return_value = { + "success": False, + "message": "Error message" + } + with pytest.raises(Exception) as exc_info: + sms_pool.get_code("order123") + assert str(exc_info.value) == "Test exception" diff --git a/ninjemail/tests/test_utils.py b/ninjemail/tests/test_utils.py new file mode 100644 index 0000000..e3747fe --- /dev/null +++ b/ninjemail/tests/test_utils.py @@ -0,0 +1,70 @@ +import pytest +from faker import Faker + +from ..utils import CountryProvider, get_birthdate, generate_missing_info + + +class TestCountryProvider: + def test_country_returns_string(self): + """Tests if CountryProvider.country returns a string.""" + fake = Faker() + fake.add_provider(CountryProvider) + country = fake.country() + assert isinstance(country, str) + + +class TestGetBirthdate: + def test_birthdate_split_correctly(self): + """Tests if get_birthdate splits the birthdate string correctly.""" + birthdate = "1990-12-31" + month, day, year = get_birthdate(birthdate) + assert month == "1990" + assert day == "12" + assert year == "31" + + def test_birthdate_split_invalid_format(self): + """Tests if get_birthdate raises an error for invalid format.""" + with pytest.raises(IndexError): + get_birthdate("invalid_format") + + +class TestGenerateMissingInfo: + def test_generate_all_missing(self): + """Tests if generate_missing_info fills all missing information.""" + username, password, first_name, last_name, country, birthdate = generate_missing_info("", "", "", "", "", "") + assert username + assert password + assert first_name + assert last_name + assert country + assert birthdate + + def test_generate_partial_missing(self): + """Tests if generate_missing_info fills only missing information.""" + username = "test_user" + password = "strong_password" + first_name = "John" + last_name = "Doe" + country = "USA" + birthdate = "1980-01-01" + filled_info = generate_missing_info(username, password, first_name, last_name, country, birthdate) + assert username == "test_user" + assert password == "strong_password" + assert first_name == "John" + assert last_name == "Doe" + assert country == "USA" + assert birthdate == "1980-01-01" + + def test_uses_faker_for_generated_data(self): + """Tests if generate_missing_info uses Faker for generated data.""" + fake1 = Faker() + fake2 = Faker() + fake1.add_provider(CountryProvider) + fake2.add_provider(CountryProvider) + + # Generate first names with different Fakers + username, _, first_name1, _, _, _ = generate_missing_info("", "", "", "", "", "") + _, _, first_name2, _, _, _ = generate_missing_info("", "", "", "", "", "") + + # Assert first names are different (likely from different Fakers) + assert first_name1 != first_name2 diff --git a/ninjemail/tests/test_webdriver_utils.py b/ninjemail/tests/test_webdriver_utils.py new file mode 100644 index 0000000..d93c0f7 --- /dev/null +++ b/ninjemail/tests/test_webdriver_utils.py @@ -0,0 +1,79 @@ +import pytest +from selenium.webdriver import Firefox, Chrome +from ..utils.webdriver_utils import create_driver + +@pytest.fixture(autouse=True) +def mock_driver_manager_installations(monkeypatch): + def mock_gecko_install(*args, **kwargs): + return 'gecko_driver_path' + + def mock_chrome_install(*args, **kwargs): + return 'chrome_driver_path' + + def mock_firefox_service(*args, **kwargs): + return None + + def mock_chrome_service(*args, **kwargs): + return None + + def mock_firefox(*args, **kwargs): + pass + + def mock_chrome(*args, **kwargs): + pass + + def mock_firefox_quit(self): + pass + + def mock_chrome_quit(self): + pass + + monkeypatch.setattr('webdriver_manager.firefox.GeckoDriverManager.install', mock_gecko_install) + monkeypatch.setattr('webdriver_manager.chrome.ChromeDriverManager.install', mock_chrome_install) + monkeypatch.setattr('selenium.webdriver.firefox.service.Service.__init__', mock_firefox_service) + monkeypatch.setattr('selenium.webdriver.chrome.service.Service.__init__', mock_chrome_service) + monkeypatch.setattr('selenium.webdriver.Firefox.__init__', mock_firefox) + monkeypatch.setattr('selenium.webdriver.Chrome.__init__', mock_chrome) + monkeypatch.setattr('selenium.webdriver.Firefox.quit', mock_firefox_quit) + monkeypatch.setattr('selenium.webdriver.Chrome.quit', mock_chrome_quit) + + +def test_create_firefox_driver_no_proxy_no_captcha(): + driver = create_driver('firefox') + assert isinstance(driver, Firefox) + driver.quit() + + +def test_create_chrome_driver_no_proxy_no_captcha(): + driver = create_driver('chrome') + assert isinstance(driver, Chrome) + driver.quit() + + +def test_create_firefox_driver_with_proxy(): + proxy_url = 'http://127.0.0.1:8080' + + driver = create_driver('firefox', proxy=proxy_url) + assert isinstance(driver, Firefox) + + driver.quit() + + +def test_create_chrome_driver_with_proxy(): + proxy_url = 'http://127.0.0.1:8080' + + driver = create_driver('chrome', proxy=proxy_url) + assert isinstance(driver, Chrome) + driver.quit() + + +def test_create_firefox_driver_with_captcha_extension(): + + driver = create_driver('firefox', captcha_extension=True) + assert isinstance(driver, Firefox) + driver.quit() + + +def test_unsupported_browser(): + with pytest.raises(ValueError): + create_driver('safari') diff --git a/requirements.txt b/requirements.txt index 58358d8..fd3dd84 100644 --- a/requirements.txt +++ b/requirements.txt @@ -7,3 +7,6 @@ toml deathbycaptcha-official Faker capsolver +pytest +pytest-mock +pytest-cov