auto-added

This commit is contained in:
2026-08-30 18:34:41 +03:00
parent c5e0213c74
commit e2022c2dae
4 changed files with 545 additions and 31 deletions
+52 -30
View File
@@ -11,8 +11,9 @@
## About me ## About me
Results-driven QA Engineer skilled in executing comprehensive test cases, API testing, and developing automated tests using Python. Known for effective collaboration with cross-functional teams to enhance application quality and user experience. Results-driven QA Engineer specializing in manual testing, API testing, and test automation using Python, pytest, and Playwright. Experienced in designing test scenarios, investigating defects, validating complex business logic, and building automated E2E test coverage.
Looking to transition into new field with background shaped by rigorous quality assurance and control processes. Skilled in identifying inefficiencies, solving complex problems, and implementing effective solutions in structured environment. Seeking to bring these transferrable skills to dynamic and innovative role.
My technical background includes backend testing, SQL, API testing, accessibility testing, CI/CD, Linux, Docker, and automated testing. I focus on combining strong test design with technical investigation to identify risks and improve product quality.
## Contact ## Contact
@@ -26,10 +27,11 @@ You can find examples of the described skills in the [Examples of my work](#exam
__Testing__ __Testing__
- can perform manual functional testing, regression testing, smoke testing, sanity testing, integration testing, visual/UI testing, API testing, accessibility testing, code review - can perform manual functional testing, regression testing, smoke testing, sanity testing, integration testing, visual/UI testing, API testing, accessibility testing and code review
- can code autotests using playwright and pytest, with Allure for test reporting (e2e, unit, integration) - can develop automated tests using Playwright and pytest, with Allure for test reporting
- experienced with E2E, unit and integration testing
- can verify fixes through regression testing and track defect resolution status - can verify fixes through regression testing and track defect resolution status
- gained hands-on experience by testing applications in my carreer path and my projects - gained hands-on experience testing applications in professional and personal projects
__Mobile & cross-platform testing__ __Mobile & cross-platform testing__
@@ -39,14 +41,20 @@ __Mobile & cross-platform testing__
__Test analysis & design__ __Test analysis & design__
- familiar with functional decomposition of products, creating state transition diagrams, writing use cases - familiar with functional decomposition of products, creating state transition diagrams and writing use cases
- can apply equivalence partitioning, boundary value analysis and methods of pairwise testing to generate test input data - can apply equivalence partitioning, boundary value analysis and pairwise testing to generate test input data
__API testing__ __API testing__
- know the difference between SOAP, REST APIs, GraphQL, gRPC, WebSockets - understand the differences between SOAP, REST, GraphQL, gRPC and WebSockets
- gained experience through manual and auto testing of APIs - gained practical experience through manual and automated API testing
- know how to manipulate requests and create test cases using the SoapUI tool and Postman tool - can manipulate requests and create test cases using SoapUI and Postman
__Accessibility testing__
- experienced in automated accessibility testing using Axe / axe-core
- can validate accessibility of different application states, including forms, validation/error states, dynamic content and themes
- able to integrate accessibility checks into E2E test scenarios
__Exploratory testing__ __Exploratory testing__
@@ -55,28 +63,30 @@ __Exploratory testing__
__Test documentation__ __Test documentation__
- can create test cases and checklists and know how and in which situations to use them effectively - can create test cases and checklists and know how and in which situations to use them effectively
- able to prepare comprehensive bug reports and provide detailed session reports and communicate with developing team to solve them - able to prepare comprehensive bug reports and provide detailed session reports
- experienced in communicating defects and test results with development teams
__SQL databases__ __SQL databases__
- can write complex requests using subqueries - can write complex queries using subqueries
- familiar with the use of aliases and wildcards - familiar with aliases and wildcards
- know the difference between joins and unions and can use them in queries - understand the difference between joins and unions and can use them in queries
- can use ORM and different DBMS - can use ORM and different DBMS
__Python__ __Python__
- can build a fullstack application using different technologies, such as ORM, DB, ASGI, WSGI, Validators and 90%+ test coverage - can build a full-stack application using technologies such as ORM, DB, ASGI, WSGI and validators
- can write a bunch of autotests for the application - can develop automated tests for applications using pytest
- experienced with unit, integration and E2E test automation
__Network__ __Network__
- know how networks work - understand basic networking concepts
- experienced with Cisco Packet Tracer for network simulation and configuration - experienced with Cisco Packet Tracer for network simulation and configuration
__CI/CD & DevOps__ __CI/CD & DevOps__
- familiar with CI/CD process and its role in the software delivery pipeline - familiar with CI/CD processes and their role in the software delivery pipeline
- can use Ansible for configuration management and automation - can use Ansible for configuration management and automation
- comfortable working in Linux/Unix environments - comfortable working in Linux/Unix environments
@@ -84,7 +94,7 @@ __CI/CD & DevOps__
__TestRail__ __TestRail__
- know how to create test cases and test suits - know how to create test cases and test suites
- able to run created test cases - able to run created test cases
- know how to use dashboards and statistics - know how to use dashboards and statistics
@@ -101,18 +111,23 @@ __API testing tools__
- HTTP Toolkit - HTTP Toolkit
- Proxyman - Proxyman
__Test reporting__ __Test automation__
- Playwright
- pytest
- Allure - Allure
- Playwright reports
__Accessibility testing__
- Axe / axe-core
__Browser developer tools__ __Browser developer tools__
- know how to test the application using console, inspector, debugging, network and storage sections - know how to test applications using console, inspector, debugger, network and storage sections
__Virtualization software__ __Virtualization software__
- able to set up and operate virtual machines in different software like Virtualbox, qemu, vmware, hyperv, docker and podman - able to set up and operate virtual machines using VirtualBox, QEMU, VMware, Hyper-V, Docker and Podman
__Ansible__ __Ansible__
@@ -136,24 +151,31 @@ The project demonstrates a complete CI/CD pipeline: Gitea Actions builds a Docke
__[The DisExcel Project](https://git.homyk.space/MH.Dmitrii/The_DisExcel_project)__ __[The DisExcel Project](https://git.homyk.space/MH.Dmitrii/The_DisExcel_project)__
My most advanced and up-to-date project — a FastAPI backend with async SQLAlchemy 2.0, JWT authentication with refresh token rotation and revocation, and a permission/group-based RBAC system. Includes layered architecture (web → service → database → models), Alembic migrations, and a full test suite (unit, integrated, e2e) with pytest, pytest-asyncio and Allure reporting. Also includes Docker and Ansible(planning) configs for deployment. My most advanced and up-to-date project — a FastAPI backend with async SQLAlchemy 2.0, JWT authentication with refresh token rotation and revocation, and a permission/group-based RBAC system. Includes layered architecture (web → service → database → models), Alembic migrations, and a full test suite (unit, integration, E2E) with pytest, pytest-asyncio and Allure reporting. Also includes Docker and Ansible configurations for deployment.
__[Auth Project](https://git.homyk.space/MH.Dmitrii/auth-project)__ __[Auth Project](https://git.homyk.space/MH.Dmitrii/auth-project)__
A basic FastAPI authentication and authorization service, built without relying on the framework's built-in auth mechanisms. Implements JWT-based login, bcrypt password hashing, and a flat permission model with privilege escalation protection. A focused example of building auth logic from scratch and understanding it deeply enough to test it effectively. A basic FastAPI authentication and authorization service, built without relying on the framework's built-in auth mechanisms. Implements JWT-based login, bcrypt password hashing, and a flat permission model with privilege escalation protection. A focused example of building authentication logic from scratch and understanding it deeply enough to test it effectively.
using console, inspector, debugging, network and storage sections
__[Nova Registration Form — QA Test Portfolio](https://git.homyk.space/MH.Dmitrii/QA-portfolio/src/branch/main/app)__ __[Nova Registration Form — QA Test Portfolio](https://git.homyk.space/MH.Dmitrii/QA-portfolio/src/branch/main/app)__
A deliberately buggy registration form (HTML/CSS/JS, no backend) built as a self-contained manual testing exercise. Includes a full test plan, test cases covering boundary value analysis, equivalence partitioning and pairwise testing, and detailed bug reports (with screenshots) for 7 seeded defects. Available in both English and Russian. Demonstrates end-to-end manual QA workflow: test planning → test design → execution → defect reporting. A deliberately buggy registration form (HTML/CSS/JS, no backend) built as a self-contained manual testing exercise. Includes a full test plan, test cases covering boundary value analysis, equivalence partitioning and pairwise testing, and detailed bug reports (with screenshots) for 7 seeded defects. Available in both English and Russian. Demonstrates an end-to-end manual QA workflow: test planning → test design → execution → defect reporting.
__[Playwright E2E Testing — Anonymized Case Study](https://git.homyk.space/MH.Dmitrii/QA-portfolio/src/branch/main/automation/playwright)__
An anonymized excerpt from an enterprise E2E automation project. The original project is proprietary, so company-specific data, credentials, URLs and internal implementation details have been removed.
The case study demonstrates Playwright and pytest automation using the Page Object Model, parametrized positive and negative scenarios, Allure reporting, password recovery flows, asynchronous email verification, dynamic security-question validation and cooldown/retry handling.
It also includes automated accessibility testing using Axe / axe-core across multiple application states, including the login page, password recovery form, security questions, validation/error states and dark theme.
## Domain experience ## Domain experience
- __Healthcare SaaS__ — tested billing modules and report templates for medical staff - __Healthcare SaaS__ — tested billing modules and report templates for medical staff
- __Banking / Fintech__ — tested mobile banking applications on iOS and Android - __Banking / Fintech__ — tested mobile banking applications on iOS and Android
- __Search engines__ - tested yandex browser, yandex maps, yandex games - __Search engines__ tested Yandex Browser, Yandex Maps and Yandex Games
## Courses and Certifications ## Courses and Certifications
QA manual, pasv - June 2023<br> QA Manual, PASV — June 2023<br>
Interactive SQL, stepik - April 2023<br> Interactive SQL, Stepik April 2023<br>
+111
View File
@@ -0,0 +1,111 @@
import pytest
import allure
from playwright.sync_api import Page, expect
@pytest.mark.login_page
class TestLoginPageAccessibility:
"""Anonymized accessibility checks from an enterprise Playwright project."""
def _check_accessibility(self, login_page_devices, accessibility_checker):
login_page_devices.wait_for_load_state("networkidle")
accessibility_checker.check(login_page_devices)
@pytest.mark.axe
def test_accessibility_login_page(
self,
login_page_devices: Page,
accessibility_checker,
):
with allure.step("Check login page accessibility"):
self._check_accessibility(login_page_devices, accessibility_checker)
@pytest.mark.axe
def test_accessibility_password_recovery(
self,
login_page_devices: Page,
login_page_object,
accessibility_checker,
):
with allure.step("Open password recovery form"):
login_page_object.forgot_password_link.click()
with allure.step("Check password recovery accessibility"):
self._check_accessibility(login_page_devices, accessibility_checker)
@pytest.mark.axe
def test_accessibility_security_questions(
self,
login_page_devices: Page,
login_page_object,
security_questions_user,
accessibility_checker,
):
with allure.step("Open password recovery form"):
login_page_object.forgot_password_link.click()
with allure.step("Fill login and email"):
login_page_object.login_field.fill(security_questions_user.login)
login_page_object.email_field.fill(security_questions_user.email)
with allure.step("Submit password recovery request"):
login_page_object.next_btn.click()
with allure.step("Check security questions accessibility"):
self._check_accessibility(login_page_devices, accessibility_checker)
@pytest.mark.axe
@pytest.mark.parametrize(
"username,password,expected_error",
[
pytest.param(
"valid_user",
"invalid_password",
"Unable to logon with specified login and password",
id="invalid-password",
),
pytest.param(
"",
"valid_password",
"Form validation failed",
id="empty-username",
),
],
)
def test_accessibility_login_error_state(
self,
login_page_devices: Page,
login_page_object,
accessibility_checker,
username: str,
password: str,
expected_error: str,
):
with allure.step("Fill login and password"):
login_page_object.login_field.fill(username)
login_page_object.password_field.fill(password)
with allure.step("Submit login form"):
login_page_object.logon_btn.click()
with allure.step("Check error message"):
expect(login_page_devices.get_by_text(expected_error)).to_contain_text(
expected_error
)
with allure.step("Check error state accessibility"):
self._check_accessibility(login_page_devices, accessibility_checker)
@pytest.mark.axe
def test_accessibility_dark_theme(
self,
login_page_devices: Page,
accessibility_checker,
):
with allure.step("Switch to dark theme"):
login_page_devices.locator("html").evaluate(
"element => element.className = 'dark'"
)
with allure.step("Check dark theme accessibility"):
self._check_accessibility(login_page_devices, accessibility_checker)
+310
View File
@@ -0,0 +1,310 @@
import re
import allure
import pytest
from playwright.sync_api import Page, expect
@pytest.mark.login_page
class TestLoginPage:
"""Anonymized E2E examples from an enterprise Playwright project."""
@pytest.mark.e2e
@pytest.mark.parametrize(
"username,password,expected_error",
[
pytest.param(
"valid_user",
"invalid_password",
"Unable to logon with specified login and password",
id="invalid-password",
),
pytest.param(
"unknown_user",
"valid_password",
"Unable to logon with specified login and password",
id="unknown-user",
),
pytest.param(
"",
"valid_password",
"Form validation failed",
id="empty-username",
),
pytest.param(
"valid_user",
"",
"Form validation failed",
id="empty-password",
),
pytest.param(
r"!@#$%^&*()_+QWERTYUIOP{}ASDFGHJKL:\"|~ZXCVBNM<>?±§ ",
r"!@#$%^&*()_+QWERTYUIOP{}ASDFGHJKL:\"|~ZXCVBNM<>?±§ ",
"Unable to logon with specified login and password",
id="special-characters",
),
pytest.param(
"qwertyuiopasdfghjklzxcvbnm" * 2,
"qwertyuiopasdfghjklzxcvbnm" * 2,
"Form validation failed",
id="overlong-input",
),
pytest.param(
"non_latin_user",
"non_latin_password",
"Form validation failed",
id="non-latin-input",
),
],
)
def test_login_negative(
self,
login_page: Page,
login_page_object,
username: str,
password: str,
expected_error: str,
):
with allure.step("Fill login and password"):
login_page_object.login_field.fill(username)
login_page_object.password_field.fill(password)
with allure.step("Click Logon button"):
login_page_object.logon_btn.click()
with allure.step("Check error message"):
expect(login_page.get_by_text(expected_error)).to_contain_text(expected_error)
@pytest.mark.e2e
def test_login_positive(self, login_page: Page, login_page_object, test_user):
with allure.step("Fill valid credentials"):
login_page_object.login_field.fill(test_user.login)
login_page_object.password_field.fill(test_user.password)
with allure.step("Click Logon button"):
login_page_object.logon_btn.click()
with allure.step("Check successful login"):
expect(login_page).not_to_have_url(login_page.url)
@pytest.mark.e2e
def test_password_reset_positive(
self,
login_page: Page,
login_page_object,
password_reset_user,
mail_checker,
):
with allure.step("Open password reset form"):
login_page_object.forgot_password_link.click()
with allure.step("Close password reset form"):
login_page_object.close_btn.click()
expect(login_page_object.reset_pass_txt).to_be_hidden()
with allure.step("Reopen password reset form"):
login_page_object.forgot_password_link.click()
with allure.step("Fill login and email"):
login_page_object.login_field.fill(password_reset_user.login)
login_page_object.email_field.fill(password_reset_user.email)
with allure.step("Submit password reset request"):
login_page_object.next_btn.click()
with allure.step("Check reset email"):
mail = mail_checker.wait_for_email(positive=True, timeout=60)
print("Received email:", mail["subject"])
with allure.step("Check confirmation message"):
expect(login_page).to_contain_text(
"Password reset confirmation message"
)
@pytest.mark.e2e
@pytest.mark.parametrize(
"login,email,expected_result",
[
pytest.param("test_user", " ", "Form validation failed", id="empty-email"),
pytest.param("test_user", "@", "Form validation failed", id="invalid-email-1"),
pytest.param("test_user", "test@", "Form validation failed", id="invalid-email-2"),
pytest.param(
"test_user",
"test@test.",
"Form validation failed",
id="invalid-email-3",
),
pytest.param(
"test_user",
".test@test.com",
"Form validation failed",
id="invalid-email-4",
),
pytest.param(
"test_user",
"te..st@test.com",
"Form validation failed",
id="invalid-email-5",
),
pytest.param(
"test_user",
"non_latin@test.com",
"Form validation failed",
id="non-latin-email",
),
pytest.param(
"test_user",
"test@test.com",
"Reset password request was accepted",
id="unknown-email-for-valid-user",
),
pytest.param(
"unknown_user",
"test@test.com",
"Reset password request was accepted",
id="unknown-user",
),
pytest.param(
"",
"test@test.com",
"Form validation failed",
id="empty-login",
),
pytest.param(
"test_user",
"test@test",
"Reset password request was accepted",
id="email-without-tld",
),
pytest.param(
"test_user",
"!@test",
"Reset password request was accepted",
id="non-standard-email-format",
),
],
)
def test_password_reset_negative(
self,
login_page: Page,
login_page_object,
mail_checker,
login: str,
email: str,
expected_result: str,
):
with allure.step("Open password reset form"):
login_page_object.forgot_password_link.click()
with allure.step("Fill login and email"):
login_page_object.login_field.fill(login)
login_page_object.email_field.fill(email)
if expected_result == "Form validation failed":
with allure.step("Verify submit button is disabled"):
expect(login_page_object.next_btn).to_be_disabled()
else:
with allure.step("Submit password reset request"):
login_page_object.next_btn.click()
with allure.step("Check application response"):
expect(login_page).to_contain_text(expected_result)
with allure.step("Check that no reset email is sent"):
mail_checker.wait_for_email(positive=False, timeout=20)
@pytest.mark.e2e
def test_password_reset_security_questions_positive(
self,
login_page: Page,
login_page_object,
security_questions_user,
mail_checker,
):
with allure.step("Open password reset form"):
login_page_object.forgot_password_link.click()
with allure.step("Fill login and email"):
login_page_object.login_field.fill(security_questions_user.login)
login_page_object.email_field.fill(security_questions_user.email)
with allure.step("Submit password reset request"):
login_page_object.next_btn.click()
answers = []
expected_questions = {
"question_type_a": "answer_a",
"question_type_b": "answer_b",
"question_type_c": "answer_c",
"question_type_d": "answer_d",
}
with allure.step("Answer security questions"):
for index in range(1, 5):
question_text = login_page.get_by_text(
re.compile(fr"Question {index}")
).inner_text()
current_answer = None
question_lower = question_text.lower()
for question_type, answer in expected_questions.items():
if question_type in question_lower:
current_answer = answer
break
assert current_answer is not None, (
f"Unknown security question: {question_text}"
)
answers.append(current_answer)
assert len(answers) == len(set(answers)), (
f"Duplicate security question detected: {question_text}"
)
login_page_object.answer_field.fill(current_answer)
login_page_object.next_btn.nth(1).click()
with allure.step("Check password reset email"):
mail = mail_checker.wait_for_email(positive=True, timeout=60)
print("Received email:", mail["subject"])
with allure.step("Check successful password reset"):
expect(login_page).to_contain_text("Password reset completed")
@pytest.mark.e2e
def test_password_reset_security_questions_negative(
self,
login_page: Page,
login_page_object,
security_questions_user,
):
with allure.step("Open password reset form"):
login_page_object.forgot_password_link.click()
with allure.step("Fill login and email"):
login_page_object.login_field.fill(security_questions_user.login)
login_page_object.email_field.fill(security_questions_user.email)
with allure.step("Submit password reset request"):
login_page_object.next_btn.click()
with allure.step("Submit invalid answers"):
for _ in range(3):
login_page_object.answer_field.fill("invalid_answer")
login_page_object.next_btn.nth(1).click()
expect(login_page).to_contain_text(
"Incorrect answer. Try again"
)
login_page_object.ok_btn.click()
with allure.step("Check cooldown timer"):
expect(login_page_object.sixty_btn).to_be_disabled()
expect(login_page_object.sixty_btn).to_contain_text(re.compile(r"\d+"))
with allure.step("Wait for cooldown to finish"):
expect(login_page_object.next_btn.nth(1)).to_be_enabled(timeout=61_000)
expect(login_page_object.next_btn.nth(1)).not_to_contain_text(
re.compile(r"\d+")
)
+71
View File
@@ -0,0 +1,71 @@
Playwright E2E Testing — Anonymized Case Study
This is an anonymized excerpt from an enterprise E2E automation project.
The original project is proprietary and cannot be published.
The code has been sanitized to remove company-specific data, credentials, URLs and internal implementation details.
Stack
* Python
* pytest
* Playwright
* Allure
* Axe / axe-core
Covered scenarios
Authentication
* valid credentials
* invalid username
* invalid password
* empty fields
* invalid characters
* boundary/long input
* error state validation
Password recovery
* valid login/email
* invalid email
* unknown user
* form validation
* email notification
* security questions
* cooldown/retry behavior
Accessibility Testing
Accessibility checks were automated using Axe / axe-core as part of the E2E test suite.
Covered UI states include:
* login page
* password recovery form
* security questions
* validation/error states
* dark theme
The accessibility checks are executed against different application states rather than only the initial page, helping detect accessibility regressions introduced by dynamic UI changes.
Security questions
* unique questions validation
* valid answers
* invalid answers
* duplicate question detection
* retry/cooldown timer
Testing approach
* Page Object Model
* parametrized tests
* positive/negative testing
* UI validation
* accessibility testing with Axe
* asynchronous email verification
* business-rule validation
* explicit assertions
* dynamic UI state validation
* E2E validation across multiple application components