From 8d9b7edecef27b85ed516a765d19fe5259b05e0d Mon Sep 17 00:00:00 2001 From: Vitaliy Gulevatiy Date: Sun, 25 Jan 2026 19:18:58 +0300 Subject: [PATCH 1/5] =?UTF-8?q?=D0=97=D0=B0=D0=B4=D0=B0=D0=BD=D0=B8=D0=B5?= =?UTF-8?q?=203?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- 3_task/.idea/.gitignore | 5 ++ 3_task/.idea/3_task.iml | 8 ++ .../inspectionProfiles/profiles_settings.xml | 6 ++ 3_task/.idea/misc.xml | 7 ++ 3_task/.idea/modules.xml | 8 ++ .../conftest.cpython-314-pytest-9.0.2.pyc | Bin 0 -> 2583 bytes 3_task/conftest.py | 54 ++++++++++++ 3_task/pages/__init__.py | 0 .../__pycache__/__init__.cpython-314.pyc | Bin 0 -> 157 bytes .../__pycache__/base_page.cpython-314.pyc | Bin 0 -> 1789 bytes .../__pycache__/feed_page.cpython-314.pyc | Bin 0 -> 2411 bytes .../__pycache__/main_page.cpython-314.pyc | Bin 0 -> 5337 bytes 3_task/pages/base_page.py | 17 ++++ 3_task/pages/feed_page.py | 20 +++++ 3_task/pages/main_page.py | 82 ++++++++++++++++++ 3_task/requirements.txt | 0 3_task/tests/__init__.py | 0 .../__pycache__/__init__.cpython-314.pyc | Bin 0 -> 157 bytes .../test_feed.cpython-314-pytest-9.0.2.pyc | Bin 0 -> 3763 bytes ...in_functional.cpython-314-pytest-9.0.2.pyc | Bin 0 -> 2541 bytes 3_task/tests/test_feed.py | 20 +++++ 3_task/tests/test_main_functional.py | 30 +++++++ 22 files changed, 257 insertions(+) create mode 100644 3_task/.idea/.gitignore create mode 100644 3_task/.idea/3_task.iml create mode 100644 3_task/.idea/inspectionProfiles/profiles_settings.xml create mode 100644 3_task/.idea/misc.xml create mode 100644 3_task/.idea/modules.xml create mode 100644 3_task/__pycache__/conftest.cpython-314-pytest-9.0.2.pyc create mode 100644 3_task/conftest.py create mode 100644 3_task/pages/__init__.py create mode 100644 3_task/pages/__pycache__/__init__.cpython-314.pyc create mode 100644 3_task/pages/__pycache__/base_page.cpython-314.pyc create mode 100644 3_task/pages/__pycache__/feed_page.cpython-314.pyc create mode 100644 3_task/pages/__pycache__/main_page.cpython-314.pyc create mode 100644 3_task/pages/base_page.py create mode 100644 3_task/pages/feed_page.py create mode 100644 3_task/pages/main_page.py create mode 100644 3_task/requirements.txt create mode 100644 3_task/tests/__init__.py create mode 100644 3_task/tests/__pycache__/__init__.cpython-314.pyc create mode 100644 3_task/tests/__pycache__/test_feed.cpython-314-pytest-9.0.2.pyc create mode 100644 3_task/tests/__pycache__/test_main_functional.cpython-314-pytest-9.0.2.pyc create mode 100644 3_task/tests/test_feed.py create mode 100644 3_task/tests/test_main_functional.py diff --git a/3_task/.idea/.gitignore b/3_task/.idea/.gitignore new file mode 100644 index 000000000..b58b603fe --- /dev/null +++ b/3_task/.idea/.gitignore @@ -0,0 +1,5 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ diff --git a/3_task/.idea/3_task.iml b/3_task/.idea/3_task.iml new file mode 100644 index 000000000..c03f621ae --- /dev/null +++ b/3_task/.idea/3_task.iml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/3_task/.idea/inspectionProfiles/profiles_settings.xml b/3_task/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 000000000..105ce2da2 --- /dev/null +++ b/3_task/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/3_task/.idea/misc.xml b/3_task/.idea/misc.xml new file mode 100644 index 000000000..590a59e60 --- /dev/null +++ b/3_task/.idea/misc.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/3_task/.idea/modules.xml b/3_task/.idea/modules.xml new file mode 100644 index 000000000..ae2fd8f77 --- /dev/null +++ b/3_task/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/3_task/__pycache__/conftest.cpython-314-pytest-9.0.2.pyc b/3_task/__pycache__/conftest.cpython-314-pytest-9.0.2.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e0ef0af6cf9db0eed8540fab1b77d0416710932f GIT binary patch literal 2583 zcma)7&2JM&6rWwM?X?}pb};#bIJQ$HQ*20^D1nxyK$_Y>Qp*&phb`8|-Xtsh#q5}T zNJtK?8Y=bBBT_G1^Oy8Wu%$$!MCCva+)Trzx6aJ&ctac7j&^5$^WNJx@9q1T4}1My zKt?azY#=g0HFG z#e{%8YuZu?>JK$YHtw(LNUv250#Dsog|&({$5;z$Rb62ceP3$D`?bGQ-FGzjP%mmb z0+tt4y_zM`M29@DX(fs`ldA~TjVl)~8b~XbRk+lEM4yq;N{ymQk4ze-1|tO<7qP3z z4#)0g9cs(9b)w5vSD{)liq^kjzlB5|#L0UU6ak2V2#IzcWEtz-DFq1`0Iyu!|bHb!`S_CNcEH<(-NA?;8ijVIUKSx}DHoz(N%6a^RypR*8i5GO# z#f730GBN08K;4mdoM@$k>xh8&NJzHCF+ckF3HD0-IL&v;07u-`|K*3{xF2~jJH)lv z>piD!50MzLIUFfxI65x54w|HD$rlmMwO4K-LSi6X8dMPGP$Og(CXER%O73Z^e2<6n!d7%u1;K^IB8 zsuSF!mP!Q`t~4rI6+s$5>@p>|q*WP^b|viAtHhRa8TZbciOu!6t$mllKci`h1A3)i z){8nSZxq&49bw0chOm77+MO>7cXPL~^q`@mgoNEtd(hAfgnP~UDOk>7ms#OBVAT_6 z7}TnBV`F1@^2QbAF8L{jvQ(?xSCtL5TGH0DP%R>*q}R)}it=#*sm6V!SgS50a!9Ja z0cjxEM6=cSl}xWm4Zd{uZa><3^i*!U#}0EU;U@(4ZwxAQ4o1n0Jr&X&3w7E|$I1Qzc@5exn&6f1)X(!R-^g=m`BM6Cf03jRD(I}!ce*`&Nj9#=EXRGaUz>=K-$@`r&iahg=NyYp~ocCC}W9QjwMPr z=rJT~ESD(Bbm=^yPmtI6fK0Ya&AEL^-d@~VY)jz-%S}S_1)8@Yl}wCbd8wh75vdN` z^Lc%v(A^Cc>KiQCRD&cZy(m&pTZ1~%u%}C+d2iCZ z@@=Yn@ukdaNm)AhY?V+~x}ORTc9j(>=3QwiHS2!ppKMDFWCi{&MiIB^ z%?fEk!tj3?#ieO_;sDJvBW0%?i?2nsqei0)X%nW`?K)~e&8%yhppb@i2e2@i;g&zG z)Jl!A_8GiNSTwbbCYd@8K@ffe;Ct|${}7BGg84&`J_IxDq4;+&eh9`pF3|HyQznZj zZ;w76eJVdoJRi8w7Lsqo0io~60mM{?qRu3f*cyE!3c?vm4|XW($X&W51R4DgksxN_ EU+&mP7ytkO literal 0 HcmV?d00001 diff --git a/3_task/conftest.py b/3_task/conftest.py new file mode 100644 index 000000000..5520e8307 --- /dev/null +++ b/3_task/conftest.py @@ -0,0 +1,54 @@ +import pytest +from selenium import webdriver +from selenium.webdriver.chrome.options import Options as ChromeOptions +from selenium.webdriver.firefox.options import Options as FirefoxOptions +from webdriver_manager.chrome import ChromeDriverManager +from webdriver_manager.firefox import GeckoDriverManager +from selenium.webdriver.chrome.service import Service as ChromeService +from selenium.webdriver.firefox.service import Service as FirefoxService + +from pages.main_page import MainPage +from pages.feed_page import FeedPage + + +BASE_URL = "https://stellarburgers.education-services.ru/" + + +@pytest.fixture(params=["chrome", "firefox"]) +def driver(request): + if request.param == "chrome": + chrome_options = ChromeOptions() + chrome_options.add_argument("--start-maximized") + + driver = webdriver.Chrome( + service=ChromeService(ChromeDriverManager().install()), + options=chrome_options + ) + else: + firefox_options = FirefoxOptions() + firefox_options.add_argument("--width=1920") + firefox_options.add_argument("--height=1080") + + driver = webdriver.Firefox( + service=FirefoxService(GeckoDriverManager().install()), + options=firefox_options + ) + + driver.implicitly_wait(5) + driver.get(BASE_URL) + + yield driver + driver.quit() + + +@pytest.fixture +def main_page(driver): + return MainPage(driver) + + +@pytest.fixture +def feed_page(driver): + main = MainPage(driver) + main.open_feed() + feed = FeedPage(driver) + return feed diff --git a/3_task/pages/__init__.py b/3_task/pages/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/3_task/pages/__pycache__/__init__.cpython-314.pyc b/3_task/pages/__pycache__/__init__.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..024a1332fc1287c4af386c634da9300f02097550 GIT binary patch literal 157 zcmdPq_I|p@<2{{|u76W#w!Y6Iz^F zR2-9(pP!u=Q<<2Tl3Ec^l$cx+lag7Glb;)79AA=HoE=k;n4Vf36Ca2KczG$)vkyYXcWk@Vi4mKGb1Bo5i^hl08GRsvH$=8 literal 0 HcmV?d00001 diff --git a/3_task/pages/__pycache__/base_page.cpython-314.pyc b/3_task/pages/__pycache__/base_page.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..113a0da072111f1255990830fbc7585a577daadb GIT binary patch literal 1789 zcmcIkO>7%Q6rNqL?RE3xk~DDyjhxt$+Xcy~(uzt+MI+jXxQEDEfpfsguwGB9QP#U= zW}KfQ)ZAz!MATC+J#gUC8%K`4atm=qsuewP>a8M3<;Z*MABq(ugv68f?YuW{-rs!l z-Wwe`M}YEIw)u}bA-|%~Bcr=GorlFf*&w!7A}gBGvbfeu`btb0Su#Opi5<%j+qecE zkW}1`=ZTegiGrntBWtX7Tkvfr)*P-tG0t|I%vG#T-N3JN#RFfuXxyW&BXasaXdDQ> zPLyU7rEkPlY?1`TPS{$8c$zY7J%a%u0hO=~m8=kDM&Xm8`Jp3O*}2QySkE#1u`H0y zZdq&R{r+aPZ?`tqE2cvHUN*!gdGbVCwPInS9@Qi8Kxph>S+UTN%-a+xR3#N}u%M+R z8WakJaPihc^%Kd2tk!~H%c<@;ex2=>h2yGfoj1LpQN2o)Be$weNEoajb&AVkb1yV0 zE$FG^Pgo>%f!P~mLn@)tF@!>xsx zOD-5Nap_BI@!rJW4!9n7w=P?Yt5!0Ci5P=K1;ROerzx0ZzRS+QNavA_vR&r36r&K9 zH&vMFAxQzbMTim;=r-9k>b}gG4zA*naX8usRwN_jBm)M>8k>A%J+vOp zJ)HY4camE=&MiI7v~#8Q*qsN-=jQO?(817&nfuAi9pyhhs;oaVH&B~8NFAmR(vS6% zsrlon`R}i{rxu@?HwF$Y{P5Aw=IsccfPNexQ8QL8?InWSO5p_Xod$ymaE{VOP;Ys- z9;Wp3mg9AI(v)s;A(h8{<_DCDQFJtkY#LZNL8(-Z;x2WR61)bTlQ>c+bjp#k&Ryj) z&!ZGa_8Uq#hEIDb>Xg9OA2A#y@*=Q5zJmVzuIuruznNP6j`liX#Fw>K1bI|bWWH)8 z!f6&1N7}vBf*X^zDDP5eCLaa6}%TkdF6gFqk(wUHL$~3;UR_ b%m8~8(=_b`x&DGIy-o~k%i1YH9v%D>>??gG literal 0 HcmV?d00001 diff --git a/3_task/pages/__pycache__/feed_page.cpython-314.pyc b/3_task/pages/__pycache__/feed_page.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..21901f592d0e3707506324fd77f474c17629daf0 GIT binary patch literal 2411 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 literal 0 HcmV?d00001 diff --git a/3_task/pages/base_page.py b/3_task/pages/base_page.py new file mode 100644 index 000000000..0777234b4 --- /dev/null +++ b/3_task/pages/base_page.py @@ -0,0 +1,17 @@ +from selenium.webdriver.support.ui import WebDriverWait +from selenium.webdriver.support import expected_conditions as EC + + +class BasePage: + def __init__(self, driver, timeout=10): + self.driver = driver + self.wait = WebDriverWait(driver, timeout) + + def find(self, locator): + return self.wait.until(EC.visibility_of_element_located(locator)) + + def click(self, locator): + element = self.wait.until(EC.presence_of_element_located(locator)) + self.driver.execute_script("arguments[0].scrollIntoView({block: 'center'});", element) + self.wait.until(EC.element_to_be_clickable(locator)) + self.driver.execute_script("arguments[0].click();", element) \ No newline at end of file diff --git a/3_task/pages/feed_page.py b/3_task/pages/feed_page.py new file mode 100644 index 000000000..3e6c4cafb --- /dev/null +++ b/3_task/pages/feed_page.py @@ -0,0 +1,20 @@ +from selenium.webdriver.common.by import By +from pages.base_page import BasePage + + +class FeedPage(BasePage): + ORDERS_TOTAL = (By.XPATH, "//p[text()='Выполнено за все время:']/following-sibling::p") + ORDERS_TODAY = (By.XPATH, "//p[text()='Выполнено за сегодня:']/following-sibling::p") + ORDERS_IN_PROGRESS = (By.XPATH, "//ul[contains(@class,'OrderFeed_orderList')]") + + def get_total_orders(self) -> int: + return int(self.find(self.ORDERS_TOTAL).text) + + def get_today_orders(self) -> int: + return int(self.find(self.ORDERS_TODAY).text) + + def refresh(self): + self.driver.refresh() + + def has_orders_in_progress(self) -> bool: + return self.find(self.ORDERS_IN_PROGRESS).is_displayed() diff --git a/3_task/pages/main_page.py b/3_task/pages/main_page.py new file mode 100644 index 000000000..114ca6b10 --- /dev/null +++ b/3_task/pages/main_page.py @@ -0,0 +1,82 @@ +from selenium.webdriver.common.by import By +from selenium.webdriver.support import expected_conditions as EC +from pages.base_page import BasePage + + +class MainPage(BasePage): + CONSTRUCTOR_TAB = (By.XPATH, "//p[text()='Конструктор']") + FEED_TAB = (By.XPATH, "//a[contains(@href,'/feed')]") + + SAUCES_TAB = (By.XPATH, "//span[text()='Соусы']") + + INGREDIENT_NAME = "Соус Spicy-X" + INGREDIENT = (By.XPATH, f"//p[text()='{INGREDIENT_NAME}']") + + CONSTRUCTOR_SECTION = ( + By.XPATH, + "//section[contains(@class,'BurgerConstructor')]" + ) + + CONSTRUCTOR_ITEMS = ( + By.XPATH, + "//section[contains(@class,'BurgerConstructor')]//li" + ) + + MODAL = (By.XPATH, "//section[contains(@class,'Modal_modal')]") + MODAL_CLOSE_BUTTON = ( + By.XPATH, + "//button[contains(@class,'Modal_modal__close')]" + ) + + def open_constructor(self): + self.click(self.CONSTRUCTOR_TAB) + + def open_feed(self): + self.click(self.FEED_TAB) + + def scroll_to_sauces(self): + tab = self.wait.until(EC.element_to_be_clickable(self.SAUCES_TAB)) + self.driver.execute_script( + "arguments[0].scrollIntoView({block: 'center'});", tab + ) + tab.click() + + def open_ingredient_modal(self): + ingredient = self.wait.until( + EC.element_to_be_clickable(self.INGREDIENT) + ) + ingredient.click() + self.wait.until(EC.visibility_of_element_located(self.MODAL)) + + def close_ingredient_modal(self): + self.click(self.MODAL_CLOSE_BUTTON) + self.wait.until(EC.invisibility_of_element_located(self.MODAL)) + + def add_ingredient_to_constructor(self): + ingredient = self.wait.until( + EC.presence_of_element_located(self.INGREDIENT) + ) + target = self.wait.until( + EC.presence_of_element_located(self.CONSTRUCTOR_SECTION) + ) + + self.driver.execute_script( + """ + const source = arguments[0]; + const target = arguments[1]; + const dataTransfer = new DataTransfer(); + + source.dispatchEvent(new DragEvent('dragstart', { dataTransfer })); + target.dispatchEvent(new DragEvent('dragover', { dataTransfer })); + target.dispatchEvent(new DragEvent('drop', { dataTransfer })); + source.dispatchEvent(new DragEvent('dragend', { dataTransfer })); + """, + ingredient, + target + ) + + def constructor_has_items(self) -> bool: + return len(self.driver.find_elements(*self.CONSTRUCTOR_ITEMS)) > 0 + + def wait_modal_closed(self): + self.wait.until(EC.invisibility_of_element_located(self.MODAL)) diff --git a/3_task/requirements.txt b/3_task/requirements.txt new file mode 100644 index 000000000..e69de29bb diff --git a/3_task/tests/__init__.py b/3_task/tests/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/3_task/tests/__pycache__/__init__.cpython-314.pyc b/3_task/tests/__pycache__/__init__.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9351149d90ef0e6920c9f001974fb611ca007571 GIT binary patch literal 157 zcmdPq_I|p@<2{{|u76W#w!Y6Iz^F zR2-9(pP!u=Q<<2Tl3Ec^l$cx+lag7Glb;)79AA=HoE=k=T3k{b6Ca2KczG$)vkyYXcWk@Vi4mKGb1Bo5i^hl09YI)-2eap literal 0 HcmV?d00001 diff --git a/3_task/tests/__pycache__/test_feed.cpython-314-pytest-9.0.2.pyc b/3_task/tests/__pycache__/test_feed.cpython-314-pytest-9.0.2.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c51956faa181b07be48debcd2435ac692bf9ec36 GIT binary patch literal 3763 zcmd^C-*4MQ9KUm1Cym>%(e4*2Gy}>Om9}H;*6ycZFx0{}f~9o=0+!pjX|y!<&W>0I zlS+p)o28&7<{w$E{*Ol+VbB&_7_`}^*` zcmCeT{h7`*f#>+oR{2ALkZEN2lL(2muYgz}?-7Mg5S#kFFrKIhy<}Xp+j;|yWJ{nC zCX(YRJLSs~6Yb+^JKam(mGT>T(0ad>DB=hWc%^L<83|Q($9?Uk$UYgf?^NhBB$xUP z{g36SmwHv#i+Qc2BYjjWSCOvm1+DY7d*1!rU3AYoSDl}nt6ArYa}kJ(&|h~hXWeto zWoOB`=3MnHE;|?9Pr>>l_p|A6qW&CZXfZi!huSbPlO!M4`X(e=j!8k!QyJ>8h_$fkGuy&r6-$4%5b}SzZF)&H;>P;xT(o+UEQ8jalfN5 zFC`IMQEU4IA4d`Y(l&Mg73mSInew?jr{ZLKn|j zY}MUdR_`IBNj@vy&r+p*A2k#EC_4=@b}T8-qa^aml4J>Wa;OZ5jp<$osMV=jxnh^AmM2vVu&}(%sx@oWDn;K^Eme#uNN81?)4g`p z(q?pw;ALL&Gg~&QhZ!@N*QG+j=QLZ@Pn#93s@b5)rC1VD%kUy(ozQqP4jAmo3vp&R z&g=@9Al_)4*<<1D^jtQ0ynQe4EgXmawF*;)aZ)SHYt^EDI?uFeyHG5f6=SY2tlFA& zvVb|T{8q)2Gic6x-F{wzJgd`2t!hIc)(i2midsdus~5=KuAY^y0k>;lxoc?Q$ejl6 zuGqOEZg9m7x5Q0%x<5gQSo?1{*m;wa~C z`*8wIOHVMkus`k@<03H-;C$ylJ2_ay8YG+4CZKV?BJ`N#GKqt`vURv8nAVF!1UHPqTqY^)qXn+lg z0=~Zf6N}Lrz(v4{Uo!w3B!CQ$D-sm(q({!Y8LP?)dVM zEzsOTy1^}wvn&ji%XleX*8R15Th!np7z|Pm#d(nF@3XQEMLiPXz2VFJtauV!7d5yg z9>aUq8jP-7hVKHG&cTP1e-Sf$%e*$bY*%!@jQXqpmiQA2(v;diXB2A{{U93xTl^TZ z@RMaVK`H%}kdMi^&R@v0@LQFLkUHP9*yChgTc)qy6OwdnEkT4MbQQ_f?nwRCGJX4= PK5up)tQ6u5 literal 0 HcmV?d00001 diff --git a/3_task/tests/__pycache__/test_main_functional.cpython-314-pytest-9.0.2.pyc b/3_task/tests/__pycache__/test_main_functional.cpython-314-pytest-9.0.2.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d1e06a37f097543d67fe29e588a1b44556ed84ea GIT binary patch literal 2541 zcmbtV+fN)-7(a7i*$dE%QY@j}p-}8{v$pt9FO7|Z);NOp;POZ2l!Q>0ErJGX-gf?lp^QF2s&Eat0w2XusU#-RsO&Z+eNM!U07tym zJQ{VQN%VdseY~b08oH4xjR-zLl{?T#jpxP>m2axcM?&(6L*<+6^3jld%c1hIx_mq& z->M2dD3$n|**BIFX!N>n7Sj5pQMwEi@*P?7%J6?qD&%K{{6;DYSs|-rnXGto3Rxoy z%A+62H^5!1`2X?3GFSnK#klHq&$YP}e{;?ndwKejPg%ZfX7Cr(82gn2*`Q!kB01EOJ&zxgmG^*Kie-$k+QZQ~=Hj`3YcO1mN#Orp`hh-dD&X z%hLn0au4Jzta(m;4_Wk7kh3gqXt$1a*Yoz)ndfWV$sZ8vf4~yp zAp3$e81l0yW!RPT7TV)zK-(R`zWSpP>@_8*kyiwKT#Z1PZl>ttwC+HibCt8_iZdfA zC;mxoqP)gQ7XlJYYNYciXE;Mcb<3e~pz_M2WBQ!tOxYzXr(vUrwMok! z*DbA}=M5Uu9DTxIWZHIxdkJ;= total_before + assert feed_page.get_today_orders() >= today_before + + +@allure.title("Заказ отображается в разделе «В работе»") +def test_order_in_progress(feed_page): + assert feed_page.has_orders_in_progress() + diff --git a/3_task/tests/test_main_functional.py b/3_task/tests/test_main_functional.py new file mode 100644 index 000000000..bfc473198 --- /dev/null +++ b/3_task/tests/test_main_functional.py @@ -0,0 +1,30 @@ +import allure +from pages.main_page import MainPage + + +@allure.title("Переход по клику на «Конструктор»") +def test_open_constructor(main_page): + main_page.open_constructor() + + +@allure.title("Переход по клику на «Лента заказов»") +def test_open_feed(main_page): + main_page.open_feed() + + +@allure.title("Открытие и закрытие модального окна ингредиента") +def test_ingredient_modal(main_page): + main_page.open_ingredient_modal() + main_page.close_ingredient_modal() + main_page.wait_modal_closed() + + +@allure.title("Ингредиент добавляется в конструктор") +def test_ingredient_added_to_constructor(main_page): + main_page.add_ingredient_to_constructor() + assert main_page.constructor_has_items() + + + + + From 973fb75ab39e1e7a50307181bd7f942c02f7bbb3 Mon Sep 17 00:00:00 2001 From: Vitaliy Gulevatiy Date: Sat, 7 Feb 2026 17:10:19 +0300 Subject: [PATCH 2/5] Add .gitignore --- .gitignore | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..1c46c2658 --- /dev/null +++ b/.gitignore @@ -0,0 +1,20 @@ +# IDE +.idea/ + +# Python +__pycache__/ +*.py[cod] + +# Pytest / Allure +.pytest_cache/ +allure-results/ +.coverage +htmlcov/ + +# Venv +.venv/ +venv/ + +# OS +.DS_Store +Thumbs.db From 80863c7ba9d7faac6568e4f198637d21dd867b53 Mon Sep 17 00:00:00 2001 From: Vitaliy Gulevatiy Date: Sat, 7 Feb 2026 17:13:03 +0300 Subject: [PATCH 3/5] Remove pycache from task 3 --- 3_task/.idea/.gitignore | 5 ----- 3_task/.idea/3_task.iml | 8 -------- .../inspectionProfiles/profiles_settings.xml | 6 ------ 3_task/.idea/misc.xml | 7 ------- 3_task/.idea/modules.xml | 8 -------- .../conftest.cpython-314-pytest-9.0.2.pyc | Bin 2583 -> 0 bytes .../pages/__pycache__/__init__.cpython-314.pyc | Bin 157 -> 0 bytes .../pages/__pycache__/base_page.cpython-314.pyc | Bin 1789 -> 0 bytes .../pages/__pycache__/feed_page.cpython-314.pyc | Bin 2411 -> 0 bytes .../pages/__pycache__/main_page.cpython-314.pyc | Bin 5337 -> 0 bytes .../tests/__pycache__/__init__.cpython-314.pyc | Bin 157 -> 0 bytes .../test_feed.cpython-314-pytest-9.0.2.pyc | Bin 3763 -> 0 bytes ..._main_functional.cpython-314-pytest-9.0.2.pyc | Bin 2541 -> 0 bytes 13 files changed, 34 deletions(-) delete mode 100644 3_task/.idea/.gitignore delete mode 100644 3_task/.idea/3_task.iml delete mode 100644 3_task/.idea/inspectionProfiles/profiles_settings.xml delete mode 100644 3_task/.idea/misc.xml delete mode 100644 3_task/.idea/modules.xml delete mode 100644 3_task/__pycache__/conftest.cpython-314-pytest-9.0.2.pyc delete mode 100644 3_task/pages/__pycache__/__init__.cpython-314.pyc delete mode 100644 3_task/pages/__pycache__/base_page.cpython-314.pyc delete mode 100644 3_task/pages/__pycache__/feed_page.cpython-314.pyc delete mode 100644 3_task/pages/__pycache__/main_page.cpython-314.pyc delete mode 100644 3_task/tests/__pycache__/__init__.cpython-314.pyc delete mode 100644 3_task/tests/__pycache__/test_feed.cpython-314-pytest-9.0.2.pyc delete mode 100644 3_task/tests/__pycache__/test_main_functional.cpython-314-pytest-9.0.2.pyc diff --git a/3_task/.idea/.gitignore b/3_task/.idea/.gitignore deleted file mode 100644 index b58b603fe..000000000 --- a/3_task/.idea/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -# Default ignored files -/shelf/ -/workspace.xml -# Editor-based HTTP Client requests -/httpRequests/ diff --git a/3_task/.idea/3_task.iml b/3_task/.idea/3_task.iml deleted file mode 100644 index c03f621ae..000000000 --- a/3_task/.idea/3_task.iml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/3_task/.idea/inspectionProfiles/profiles_settings.xml b/3_task/.idea/inspectionProfiles/profiles_settings.xml deleted file mode 100644 index 105ce2da2..000000000 --- a/3_task/.idea/inspectionProfiles/profiles_settings.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - \ No newline at end of file diff --git a/3_task/.idea/misc.xml b/3_task/.idea/misc.xml deleted file mode 100644 index 590a59e60..000000000 --- a/3_task/.idea/misc.xml +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/3_task/.idea/modules.xml b/3_task/.idea/modules.xml deleted file mode 100644 index ae2fd8f77..000000000 --- a/3_task/.idea/modules.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/3_task/__pycache__/conftest.cpython-314-pytest-9.0.2.pyc b/3_task/__pycache__/conftest.cpython-314-pytest-9.0.2.pyc deleted file mode 100644 index e0ef0af6cf9db0eed8540fab1b77d0416710932f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2583 zcma)7&2JM&6rWwM?X?}pb};#bIJQ$HQ*20^D1nxyK$_Y>Qp*&phb`8|-Xtsh#q5}T zNJtK?8Y=bBBT_G1^Oy8Wu%$$!MCCva+)Trzx6aJ&ctac7j&^5$^WNJx@9q1T4}1My zKt?azY#=g0HFG z#e{%8YuZu?>JK$YHtw(LNUv250#Dsog|&({$5;z$Rb62ceP3$D`?bGQ-FGzjP%mmb z0+tt4y_zM`M29@DX(fs`ldA~TjVl)~8b~XbRk+lEM4yq;N{ymQk4ze-1|tO<7qP3z z4#)0g9cs(9b)w5vSD{)liq^kjzlB5|#L0UU6ak2V2#IzcWEtz-DFq1`0Iyu!|bHb!`S_CNcEH<(-NA?;8ijVIUKSx}DHoz(N%6a^RypR*8i5GO# z#f730GBN08K;4mdoM@$k>xh8&NJzHCF+ckF3HD0-IL&v;07u-`|K*3{xF2~jJH)lv z>piD!50MzLIUFfxI65x54w|HD$rlmMwO4K-LSi6X8dMPGP$Og(CXER%O73Z^e2<6n!d7%u1;K^IB8 zsuSF!mP!Q`t~4rI6+s$5>@p>|q*WP^b|viAtHhRa8TZbciOu!6t$mllKci`h1A3)i z){8nSZxq&49bw0chOm77+MO>7cXPL~^q`@mgoNEtd(hAfgnP~UDOk>7ms#OBVAT_6 z7}TnBV`F1@^2QbAF8L{jvQ(?xSCtL5TGH0DP%R>*q}R)}it=#*sm6V!SgS50a!9Ja z0cjxEM6=cSl}xWm4Zd{uZa><3^i*!U#}0EU;U@(4ZwxAQ4o1n0Jr&X&3w7E|$I1Qzc@5exn&6f1)X(!R-^g=m`BM6Cf03jRD(I}!ce*`&Nj9#=EXRGaUz>=K-$@`r&iahg=NyYp~ocCC}W9QjwMPr z=rJT~ESD(Bbm=^yPmtI6fK0Ya&AEL^-d@~VY)jz-%S}S_1)8@Yl}wCbd8wh75vdN` z^Lc%v(A^Cc>KiQCRD&cZy(m&pTZ1~%u%}C+d2iCZ z@@=Yn@ukdaNm)AhY?V+~x}ORTc9j(>=3QwiHS2!ppKMDFWCi{&MiIB^ z%?fEk!tj3?#ieO_;sDJvBW0%?i?2nsqei0)X%nW`?K)~e&8%yhppb@i2e2@i;g&zG z)Jl!A_8GiNSTwbbCYd@8K@ffe;Ct|${}7BGg84&`J_IxDq4;+&eh9`pF3|HyQznZj zZ;w76eJVdoJRi8w7Lsqo0io~60mM{?qRu3f*cyE!3c?vm4|XW($X&W51R4DgksxN_ EU+&mP7ytkO diff --git a/3_task/pages/__pycache__/__init__.cpython-314.pyc b/3_task/pages/__pycache__/__init__.cpython-314.pyc deleted file mode 100644 index 024a1332fc1287c4af386c634da9300f02097550..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 157 zcmdPq_I|p@<2{{|u76W#w!Y6Iz^F zR2-9(pP!u=Q<<2Tl3Ec^l$cx+lag7Glb;)79AA=HoE=k;n4Vf36Ca2KczG$)vkyYXcWk@Vi4mKGb1Bo5i^hl08GRsvH$=8 diff --git a/3_task/pages/__pycache__/base_page.cpython-314.pyc b/3_task/pages/__pycache__/base_page.cpython-314.pyc deleted file mode 100644 index 113a0da072111f1255990830fbc7585a577daadb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1789 zcmcIkO>7%Q6rNqL?RE3xk~DDyjhxt$+Xcy~(uzt+MI+jXxQEDEfpfsguwGB9QP#U= zW}KfQ)ZAz!MATC+J#gUC8%K`4atm=qsuewP>a8M3<;Z*MABq(ugv68f?YuW{-rs!l z-Wwe`M}YEIw)u}bA-|%~Bcr=GorlFf*&w!7A}gBGvbfeu`btb0Su#Opi5<%j+qecE zkW}1`=ZTegiGrntBWtX7Tkvfr)*P-tG0t|I%vG#T-N3JN#RFfuXxyW&BXasaXdDQ> zPLyU7rEkPlY?1`TPS{$8c$zY7J%a%u0hO=~m8=kDM&Xm8`Jp3O*}2QySkE#1u`H0y zZdq&R{r+aPZ?`tqE2cvHUN*!gdGbVCwPInS9@Qi8Kxph>S+UTN%-a+xR3#N}u%M+R z8WakJaPihc^%Kd2tk!~H%c<@;ex2=>h2yGfoj1LpQN2o)Be$weNEoajb&AVkb1yV0 zE$FG^Pgo>%f!P~mLn@)tF@!>xsx zOD-5Nap_BI@!rJW4!9n7w=P?Yt5!0Ci5P=K1;ROerzx0ZzRS+QNavA_vR&r36r&K9 zH&vMFAxQzbMTim;=r-9k>b}gG4zA*naX8usRwN_jBm)M>8k>A%J+vOp zJ)HY4camE=&MiI7v~#8Q*qsN-=jQO?(817&nfuAi9pyhhs;oaVH&B~8NFAmR(vS6% zsrlon`R}i{rxu@?HwF$Y{P5Aw=IsccfPNexQ8QL8?InWSO5p_Xod$ymaE{VOP;Ys- z9;Wp3mg9AI(v)s;A(h8{<_DCDQFJtkY#LZNL8(-Z;x2WR61)bTlQ>c+bjp#k&Ryj) z&!ZGa_8Uq#hEIDb>Xg9OA2A#y@*=Q5zJmVzuIuruznNP6j`liX#Fw>K1bI|bWWH)8 z!f6&1N7}vBf*X^zDDP5eCLaa6}%TkdF6gFqk(wUHL$~3;UR_ b%m8~8(=_b`x&DGIy-o~k%i1YH9v%D>>??gG diff --git a/3_task/pages/__pycache__/feed_page.cpython-314.pyc b/3_task/pages/__pycache__/feed_page.cpython-314.pyc deleted file mode 100644 index 21901f592d0e3707506324fd77f474c17629daf0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2411 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 diff --git a/3_task/tests/__pycache__/__init__.cpython-314.pyc b/3_task/tests/__pycache__/__init__.cpython-314.pyc deleted file mode 100644 index 9351149d90ef0e6920c9f001974fb611ca007571..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 157 zcmdPq_I|p@<2{{|u76W#w!Y6Iz^F zR2-9(pP!u=Q<<2Tl3Ec^l$cx+lag7Glb;)79AA=HoE=k=T3k{b6Ca2KczG$)vkyYXcWk@Vi4mKGb1Bo5i^hl09YI)-2eap diff --git a/3_task/tests/__pycache__/test_feed.cpython-314-pytest-9.0.2.pyc b/3_task/tests/__pycache__/test_feed.cpython-314-pytest-9.0.2.pyc deleted file mode 100644 index c51956faa181b07be48debcd2435ac692bf9ec36..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3763 zcmd^C-*4MQ9KUm1Cym>%(e4*2Gy}>Om9}H;*6ycZFx0{}f~9o=0+!pjX|y!<&W>0I zlS+p)o28&7<{w$E{*Ol+VbB&_7_`}^*` zcmCeT{h7`*f#>+oR{2ALkZEN2lL(2muYgz}?-7Mg5S#kFFrKIhy<}Xp+j;|yWJ{nC zCX(YRJLSs~6Yb+^JKam(mGT>T(0ad>DB=hWc%^L<83|Q($9?Uk$UYgf?^NhBB$xUP z{g36SmwHv#i+Qc2BYjjWSCOvm1+DY7d*1!rU3AYoSDl}nt6ArYa}kJ(&|h~hXWeto zWoOB`=3MnHE;|?9Pr>>l_p|A6qW&CZXfZi!huSbPlO!M4`X(e=j!8k!QyJ>8h_$fkGuy&r6-$4%5b}SzZF)&H;>P;xT(o+UEQ8jalfN5 zFC`IMQEU4IA4d`Y(l&Mg73mSInew?jr{ZLKn|j zY}MUdR_`IBNj@vy&r+p*A2k#EC_4=@b}T8-qa^aml4J>Wa;OZ5jp<$osMV=jxnh^AmM2vVu&}(%sx@oWDn;K^Eme#uNN81?)4g`p z(q?pw;ALL&Gg~&QhZ!@N*QG+j=QLZ@Pn#93s@b5)rC1VD%kUy(ozQqP4jAmo3vp&R z&g=@9Al_)4*<<1D^jtQ0ynQe4EgXmawF*;)aZ)SHYt^EDI?uFeyHG5f6=SY2tlFA& zvVb|T{8q)2Gic6x-F{wzJgd`2t!hIc)(i2midsdus~5=KuAY^y0k>;lxoc?Q$ejl6 zuGqOEZg9m7x5Q0%x<5gQSo?1{*m;wa~C z`*8wIOHVMkus`k@<03H-;C$ylJ2_ay8YG+4CZKV?BJ`N#GKqt`vURv8nAVF!1UHPqTqY^)qXn+lg z0=~Zf6N}Lrz(v4{Uo!w3B!CQ$D-sm(q({!Y8LP?)dVM zEzsOTy1^}wvn&ji%XleX*8R15Th!np7z|Pm#d(nF@3XQEMLiPXz2VFJtauV!7d5yg z9>aUq8jP-7hVKHG&cTP1e-Sf$%e*$bY*%!@jQXqpmiQA2(v;diXB2A{{U93xTl^TZ z@RMaVK`H%}kdMi^&R@v0@LQFLkUHP9*yChgTc)qy6OwdnEkT4MbQQ_f?nwRCGJX4= PK5up)tQ6u5 diff --git a/3_task/tests/__pycache__/test_main_functional.cpython-314-pytest-9.0.2.pyc b/3_task/tests/__pycache__/test_main_functional.cpython-314-pytest-9.0.2.pyc deleted file mode 100644 index d1e06a37f097543d67fe29e588a1b44556ed84ea..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2541 zcmbtV+fN)-7(a7i*$dE%QY@j}p-}8{v$pt9FO7|Z);NOp;POZ2l!Q>0ErJGX-gf?lp^QF2s&Eat0w2XusU#-RsO&Z+eNM!U07tym zJQ{VQN%VdseY~b08oH4xjR-zLl{?T#jpxP>m2axcM?&(6L*<+6^3jld%c1hIx_mq& z->M2dD3$n|**BIFX!N>n7Sj5pQMwEi@*P?7%J6?qD&%K{{6;DYSs|-rnXGto3Rxoy z%A+62H^5!1`2X?3GFSnK#klHq&$YP}e{;?ndwKejPg%ZfX7Cr(82gn2*`Q!kB01EOJ&zxgmG^*Kie-$k+QZQ~=Hj`3YcO1mN#Orp`hh-dD&X z%hLn0au4Jzta(m;4_Wk7kh3gqXt$1a*Yoz)ndfWV$sZ8vf4~yp zAp3$e81l0yW!RPT7TV)zK-(R`zWSpP>@_8*kyiwKT#Z1PZl>ttwC+HibCt8_iZdfA zC;mxoqP)gQ7XlJYYNYciXE;Mcb<3e~pz_M2WBQ!tOxYzXr(vUrwMok! z*DbA}=M5Uu9DTxIWZHIxdkJ; Date: Sat, 7 Feb 2026 18:45:01 +0300 Subject: [PATCH 4/5] fix: reviewer comments for task 3 (pages, tests, allure steps) --- 3_task/pages/base_page.py | 36 ++++++++++++-- 3_task/pages/feed_page.py | 24 ++++++++-- 3_task/pages/main_page.py | 48 +++++++++++++------ 3_task/tests/test_feed.py | 72 ++++++++++++++++++++++++---- 3_task/tests/test_main_functional.py | 52 ++++++++++++++------ 5 files changed, 184 insertions(+), 48 deletions(-) diff --git a/3_task/pages/base_page.py b/3_task/pages/base_page.py index 0777234b4..a8f6215e2 100644 --- a/3_task/pages/base_page.py +++ b/3_task/pages/base_page.py @@ -1,3 +1,4 @@ +import allure from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC @@ -7,11 +8,38 @@ def __init__(self, driver, timeout=10): self.driver = driver self.wait = WebDriverWait(driver, timeout) + @allure.step("Ожидание видимости элемента {locator}") def find(self, locator): return self.wait.until(EC.visibility_of_element_located(locator)) + @allure.step("Ожидание кликабельности элемента {locator}") + def find_clickable(self, locator): + return self.wait.until(EC.element_to_be_clickable(locator)) + + @allure.step("Клик по элементу {locator}") def click(self, locator): - element = self.wait.until(EC.presence_of_element_located(locator)) - self.driver.execute_script("arguments[0].scrollIntoView({block: 'center'});", element) - self.wait.until(EC.element_to_be_clickable(locator)) - self.driver.execute_script("arguments[0].click();", element) \ No newline at end of file + element = self.find_clickable(locator) + self.driver.execute_script( + "arguments[0].scrollIntoView({block: 'center'});", element + ) + self.driver.execute_script("arguments[0].click();", element) + + @allure.step("Проверка наличия элемента {locator}") + def is_visible(self, locator) -> bool: + try: + self.find(locator) + return True + except Exception: + return False + + @allure.step("Ожидание исчезновения элемента {locator}") + def wait_until_invisible(self, locator): + self.wait.until(EC.invisibility_of_element_located(locator)) + + @allure.step("Получение списка элементов {locator}") + def find_all(self, locator): + return self.driver.find_elements(*locator) + + @allure.step("Обновление страницы") + def refresh(self): + self.driver.refresh() diff --git a/3_task/pages/feed_page.py b/3_task/pages/feed_page.py index 3e6c4cafb..5d45242de 100644 --- a/3_task/pages/feed_page.py +++ b/3_task/pages/feed_page.py @@ -1,20 +1,34 @@ +import allure from selenium.webdriver.common.by import By from pages.base_page import BasePage class FeedPage(BasePage): - ORDERS_TOTAL = (By.XPATH, "//p[text()='Выполнено за все время:']/following-sibling::p") - ORDERS_TODAY = (By.XPATH, "//p[text()='Выполнено за сегодня:']/following-sibling::p") - ORDERS_IN_PROGRESS = (By.XPATH, "//ul[contains(@class,'OrderFeed_orderList')]") + ORDERS_TOTAL = ( + By.XPATH, + "//p[text()='Выполнено за все время:']/following-sibling::p" + ) + ORDERS_TODAY = ( + By.XPATH, + "//p[text()='Выполнено за сегодня:']/following-sibling::p" + ) + ORDERS_IN_PROGRESS = ( + By.XPATH, + "//ul[contains(@class,'OrderFeed_orderList')]" + ) + @allure.step("Получение количества заказов за всё время") def get_total_orders(self) -> int: return int(self.find(self.ORDERS_TOTAL).text) + @allure.step("Получение количества заказов за сегодня") def get_today_orders(self) -> int: return int(self.find(self.ORDERS_TODAY).text) - def refresh(self): - self.driver.refresh() + @allure.step("Обновление страницы ленты заказов") + def refresh_feed(self): + self.refresh() + @allure.step("Проверка наличия заказов в статусе «В работе»") def has_orders_in_progress(self) -> bool: return self.find(self.ORDERS_IN_PROGRESS).is_displayed() diff --git a/3_task/pages/main_page.py b/3_task/pages/main_page.py index 114ca6b10..7facfb4a7 100644 --- a/3_task/pages/main_page.py +++ b/3_task/pages/main_page.py @@ -1,14 +1,18 @@ +import allure from selenium.webdriver.common.by import By from selenium.webdriver.support import expected_conditions as EC from pages.base_page import BasePage class MainPage(BasePage): + CONSTRUCTOR_TAB = (By.XPATH, "//p[text()='Конструктор']") FEED_TAB = (By.XPATH, "//a[contains(@href,'/feed')]") - SAUCES_TAB = (By.XPATH, "//span[text()='Соусы']") + CONSTRUCTOR_HEADER = (By.XPATH, "//h1[text()='Соберите бургер']") + FEED_HEADER = (By.XPATH, "//h1[text()='Лента заказов']") + SAUCES_TAB = (By.XPATH, "//span[text()='Соусы']") INGREDIENT_NAME = "Соус Spicy-X" INGREDIENT = (By.XPATH, f"//p[text()='{INGREDIENT_NAME}']") @@ -28,30 +32,48 @@ class MainPage(BasePage): "//button[contains(@class,'Modal_modal__close')]" ) + @allure.step("Открыть конструктор") def open_constructor(self): self.click(self.CONSTRUCTOR_TAB) + @allure.step("Открыть ленту заказов") def open_feed(self): self.click(self.FEED_TAB) - def scroll_to_sauces(self): - tab = self.wait.until(EC.element_to_be_clickable(self.SAUCES_TAB)) - self.driver.execute_script( - "arguments[0].scrollIntoView({block: 'center'});", tab - ) - tab.click() + @allure.step("Проверить, что конструктор открыт") + def is_constructor_opened(self) -> bool: + return len(self.driver.find_elements(*self.CONSTRUCTOR_HEADER)) > 0 + + @allure.step("Проверить, что лента заказов открыта") + def is_feed_opened(self) -> bool: + return len(self.driver.find_elements(*self.FEED_HEADER)) > 0 + @allure.step("Открыть модальное окно ингредиента") def open_ingredient_modal(self): - ingredient = self.wait.until( + self.wait.until( EC.element_to_be_clickable(self.INGREDIENT) + ).click() + + self.wait.until( + EC.visibility_of_element_located(self.MODAL) ) - ingredient.click() - self.wait.until(EC.visibility_of_element_located(self.MODAL)) + @allure.step("Проверить, что модальное окно ингредиента открыто") + def is_ingredient_modal_opened(self) -> bool: + elements = self.driver.find_elements(*self.MODAL) + return len(elements) > 0 and elements[0].is_displayed() + + @allure.step("Закрыть модальное окно ингредиента") def close_ingredient_modal(self): self.click(self.MODAL_CLOSE_BUTTON) - self.wait.until(EC.invisibility_of_element_located(self.MODAL)) + @allure.step("Дождаться закрытия модального окна") + def wait_modal_closed(self): + self.wait.until( + EC.invisibility_of_element_located(self.MODAL) + ) + + @allure.step("Добавить ингредиент в конструктор") def add_ingredient_to_constructor(self): ingredient = self.wait.until( EC.presence_of_element_located(self.INGREDIENT) @@ -75,8 +97,6 @@ def add_ingredient_to_constructor(self): target ) + @allure.step("Проверить, что в конструкторе есть ингредиенты") def constructor_has_items(self) -> bool: return len(self.driver.find_elements(*self.CONSTRUCTOR_ITEMS)) > 0 - - def wait_modal_closed(self): - self.wait.until(EC.invisibility_of_element_located(self.MODAL)) diff --git a/3_task/tests/test_feed.py b/3_task/tests/test_feed.py index 17e9e0b72..7c7f1cdd1 100644 --- a/3_task/tests/test_feed.py +++ b/3_task/tests/test_feed.py @@ -1,20 +1,72 @@ import allure +import requests + from pages.feed_page import FeedPage from pages.main_page import MainPage +BASE_URL = "https://stellarburgers.education-services.ru" + + +@allure.feature("Лента заказов") +class TestFeed: + + @allure.title("Счётчики заказов увеличиваются после оформления заказа") + def test_orders_counters(self, driver): + main_page = MainPage(driver) + feed_page = FeedPage(driver) + + with allure.step("Переход в ленту заказов"): + main_page.open_feed() + + with allure.step("Фиксация текущих значений счётчиков"): + total_before = feed_page.get_total_orders() + today_before = feed_page.get_today_orders() + + with allure.step("Получение ингредиентов"): + ingredients = requests.get( + f"{BASE_URL}/api/ingredients" + ).json()["data"] + + ingredient_ids = [ingredients[0]["_id"]] + + with allure.step("Оформление заказа через API"): + response = requests.post( + f"{BASE_URL}/api/orders", + json={"ingredients": ingredient_ids} + ) + assert response.status_code == 200 + + with allure.step("Обновление ленты заказов"): + feed_page.refresh_feed() + + with allure.step("Проверка обновления счётчиков"): + assert feed_page.get_total_orders() >= total_before + assert feed_page.get_today_orders() >= 0 + + @allure.title("Заказ отображается в разделе «В работе»") + def test_order_in_progress(self, driver): + main_page = MainPage(driver) + feed_page = FeedPage(driver) -@allure.title("Счётчики заказов увеличиваются") -def test_orders_counters(feed_page): - total_before = feed_page.get_total_orders() - today_before = feed_page.get_today_orders() + with allure.step("Переход в ленту заказов"): + main_page.open_feed() - feed_page.refresh() + with allure.step("Получение ингредиентов"): + ingredients = requests.get( + f"{BASE_URL}/api/ingredients" + ).json()["data"] - assert feed_page.get_total_orders() >= total_before - assert feed_page.get_today_orders() >= today_before + ingredient_ids = [ingredients[0]["_id"]] + with allure.step("Создание заказа"): + response = requests.post( + f"{BASE_URL}/api/orders", + json={"ingredients": ingredient_ids} + ) + assert response.status_code == 200 -@allure.title("Заказ отображается в разделе «В работе»") -def test_order_in_progress(feed_page): - assert feed_page.has_orders_in_progress() + with allure.step("Обновление ленты"): + feed_page.refresh_feed() + with allure.step("Проверка наличия заказов в работе"): + assert feed_page.has_orders_in_progress() diff --git a/3_task/tests/test_main_functional.py b/3_task/tests/test_main_functional.py index bfc473198..3648649a9 100644 --- a/3_task/tests/test_main_functional.py +++ b/3_task/tests/test_main_functional.py @@ -1,30 +1,52 @@ import allure + from pages.main_page import MainPage -@allure.title("Переход по клику на «Конструктор»") -def test_open_constructor(main_page): - main_page.open_constructor() +@allure.feature("Главная страница") +class TestMainFunctional: + + @allure.title("Переход по клику на «Конструктор»") + def test_open_constructor(self, driver): + main_page = MainPage(driver) + + with allure.step("Клик по вкладке «Конструктор»"): + main_page.open_constructor() + with allure.step("Проверка, что конструктор открыт"): + assert main_page.is_constructor_opened() -@allure.title("Переход по клику на «Лента заказов»") -def test_open_feed(main_page): - main_page.open_feed() + @allure.title("Переход по клику на «Лента заказов»") + def test_open_feed(self, driver): + main_page = MainPage(driver) + with allure.step("Клик по вкладке «Лента заказов»"): + main_page.open_feed() -@allure.title("Открытие и закрытие модального окна ингредиента") -def test_ingredient_modal(main_page): - main_page.open_ingredient_modal() - main_page.close_ingredient_modal() - main_page.wait_modal_closed() + with allure.step("Проверка, что открыта лента заказов"): + assert main_page.is_feed_opened() + @allure.title("Открытие и закрытие модального окна ингредиента") + def test_ingredient_modal(self, driver): + main_page = MainPage(driver) -@allure.title("Ингредиент добавляется в конструктор") -def test_ingredient_added_to_constructor(main_page): - main_page.add_ingredient_to_constructor() - assert main_page.constructor_has_items() + with allure.step("Открытие модального окна ингредиента"): + main_page.open_ingredient_modal() + assert main_page.is_ingredient_modal_opened() + with allure.step("Закрытие модального окна ингредиента"): + main_page.close_ingredient_modal() + main_page.wait_modal_closed() + with allure.step("Проверка, что модальное окно закрыто"): + assert not main_page.is_ingredient_modal_opened() + @allure.title("Ингредиент добавляется в конструктор") + def test_ingredient_added_to_constructor(self, driver): + main_page = MainPage(driver) + with allure.step("Добавление ингредиента в конструктор"): + main_page.add_ingredient_to_constructor() + with allure.step("Проверка, что в конструкторе появился ингредиент"): + assert main_page.constructor_has_items() From cb6b4218787a8fd6738221a42c559ea4b3adea11 Mon Sep 17 00:00:00 2001 From: Vitaliy Gulevatiy Date: Sun, 8 Feb 2026 17:04:10 +0300 Subject: [PATCH 5/5] fix: refactor code, delet API and add UI test --- 3_task/conftest.py | 30 +++--------- 3_task/pages/base_page.py | 68 ++++++++++++++++++---------- 3_task/pages/feed_page.py | 9 ++-- 3_task/pages/main_page.py | 44 +++++++----------- 3_task/tests/test_feed.py | 61 +++++++++---------------- 3_task/tests/test_main_functional.py | 16 +++---- 6 files changed, 100 insertions(+), 128 deletions(-) diff --git a/3_task/conftest.py b/3_task/conftest.py index 5520e8307..7911fde6c 100644 --- a/3_task/conftest.py +++ b/3_task/conftest.py @@ -7,9 +7,6 @@ from selenium.webdriver.chrome.service import Service as ChromeService from selenium.webdriver.firefox.service import Service as FirefoxService -from pages.main_page import MainPage -from pages.feed_page import FeedPage - BASE_URL = "https://stellarburgers.education-services.ru/" @@ -17,21 +14,21 @@ @pytest.fixture(params=["chrome", "firefox"]) def driver(request): if request.param == "chrome": - chrome_options = ChromeOptions() - chrome_options.add_argument("--start-maximized") + options = ChromeOptions() + options.add_argument("--start-maximized") driver = webdriver.Chrome( service=ChromeService(ChromeDriverManager().install()), - options=chrome_options + options=options ) else: - firefox_options = FirefoxOptions() - firefox_options.add_argument("--width=1920") - firefox_options.add_argument("--height=1080") + options = FirefoxOptions() + options.add_argument("--width=1920") + options.add_argument("--height=1080") driver = webdriver.Firefox( service=FirefoxService(GeckoDriverManager().install()), - options=firefox_options + options=options ) driver.implicitly_wait(5) @@ -39,16 +36,3 @@ def driver(request): yield driver driver.quit() - - -@pytest.fixture -def main_page(driver): - return MainPage(driver) - - -@pytest.fixture -def feed_page(driver): - main = MainPage(driver) - main.open_feed() - feed = FeedPage(driver) - return feed diff --git a/3_task/pages/base_page.py b/3_task/pages/base_page.py index a8f6215e2..a25382a28 100644 --- a/3_task/pages/base_page.py +++ b/3_task/pages/base_page.py @@ -4,42 +4,62 @@ class BasePage: + def __init__(self, driver, timeout=10): - self.driver = driver - self.wait = WebDriverWait(driver, timeout) + self._driver = driver + self._wait = WebDriverWait(driver, timeout) + + # ---------- базовые ожидания ---------- @allure.step("Ожидание видимости элемента {locator}") - def find(self, locator): - return self.wait.until(EC.visibility_of_element_located(locator)) + def wait_visible(self, locator): + return self._wait.until(EC.visibility_of_element_located(locator)) @allure.step("Ожидание кликабельности элемента {locator}") - def find_clickable(self, locator): - return self.wait.until(EC.element_to_be_clickable(locator)) + def wait_clickable(self, locator): + return self._wait.until(EC.element_to_be_clickable(locator)) + + @allure.step("Ожидание присутствия элемента {locator}") + def wait_present(self, locator): + return self._wait.until(EC.presence_of_element_located(locator)) + + @allure.step("Ожидание исчезновения элемента {locator}") + def wait_invisible(self, locator): + self._wait.until(EC.invisibility_of_element_located(locator)) + + # ---------- действия ---------- @allure.step("Клик по элементу {locator}") def click(self, locator): - element = self.find_clickable(locator) - self.driver.execute_script( - "arguments[0].scrollIntoView({block: 'center'});", element + element = self.wait_clickable(locator) + self._driver.execute_script( + "arguments[0].scrollIntoView({block: 'center'});", + element ) - self.driver.execute_script("arguments[0].click();", element) + self._driver.execute_script("arguments[0].click();", element) + + @allure.step("Выполнение JS-скрипта") + def execute_js(self, script, *args): + self._driver.execute_script(script, *args) + + @allure.step("Обновление страницы") + def refresh_page(self): + self._driver.refresh() - @allure.step("Проверка наличия элемента {locator}") + # ---------- получение данных ---------- + + @allure.step("Получение текста элемента {locator}") + def get_text(self, locator) -> str: + return self.wait_visible(locator).text + + @allure.step("Подсчёт элементов {locator}") + def count_elements(self, locator) -> int: + return len(self._driver.find_elements(*locator)) + + @allure.step("Проверка видимости элемента {locator}") def is_visible(self, locator) -> bool: try: - self.find(locator) + self.wait_visible(locator) return True except Exception: return False - - @allure.step("Ожидание исчезновения элемента {locator}") - def wait_until_invisible(self, locator): - self.wait.until(EC.invisibility_of_element_located(locator)) - - @allure.step("Получение списка элементов {locator}") - def find_all(self, locator): - return self.driver.find_elements(*locator) - - @allure.step("Обновление страницы") - def refresh(self): - self.driver.refresh() diff --git a/3_task/pages/feed_page.py b/3_task/pages/feed_page.py index 5d45242de..467aa971c 100644 --- a/3_task/pages/feed_page.py +++ b/3_task/pages/feed_page.py @@ -4,6 +4,7 @@ class FeedPage(BasePage): + ORDERS_TOTAL = ( By.XPATH, "//p[text()='Выполнено за все время:']/following-sibling::p" @@ -19,16 +20,16 @@ class FeedPage(BasePage): @allure.step("Получение количества заказов за всё время") def get_total_orders(self) -> int: - return int(self.find(self.ORDERS_TOTAL).text) + return int(self.get_text(self.ORDERS_TOTAL)) @allure.step("Получение количества заказов за сегодня") def get_today_orders(self) -> int: - return int(self.find(self.ORDERS_TODAY).text) + return int(self.get_text(self.ORDERS_TODAY)) @allure.step("Обновление страницы ленты заказов") def refresh_feed(self): - self.refresh() + self.refresh_page() @allure.step("Проверка наличия заказов в статусе «В работе»") def has_orders_in_progress(self) -> bool: - return self.find(self.ORDERS_IN_PROGRESS).is_displayed() + return self.is_visible(self.ORDERS_IN_PROGRESS) diff --git a/3_task/pages/main_page.py b/3_task/pages/main_page.py index 7facfb4a7..40f4adb6b 100644 --- a/3_task/pages/main_page.py +++ b/3_task/pages/main_page.py @@ -1,6 +1,5 @@ import allure from selenium.webdriver.common.by import By -from selenium.webdriver.support import expected_conditions as EC from pages.base_page import BasePage @@ -12,7 +11,6 @@ class MainPage(BasePage): CONSTRUCTOR_HEADER = (By.XPATH, "//h1[text()='Соберите бургер']") FEED_HEADER = (By.XPATH, "//h1[text()='Лента заказов']") - SAUCES_TAB = (By.XPATH, "//span[text()='Соусы']") INGREDIENT_NAME = "Соус Spicy-X" INGREDIENT = (By.XPATH, f"//p[text()='{INGREDIENT_NAME}']") @@ -32,6 +30,8 @@ class MainPage(BasePage): "//button[contains(@class,'Modal_modal__close')]" ) + # ---------- навигация ---------- + @allure.step("Открыть конструктор") def open_constructor(self): self.click(self.CONSTRUCTOR_TAB) @@ -40,28 +40,22 @@ def open_constructor(self): def open_feed(self): self.click(self.FEED_TAB) + # ---------- проверки ---------- + @allure.step("Проверить, что конструктор открыт") def is_constructor_opened(self) -> bool: - return len(self.driver.find_elements(*self.CONSTRUCTOR_HEADER)) > 0 + return self.count_elements(self.CONSTRUCTOR_HEADER) > 0 @allure.step("Проверить, что лента заказов открыта") def is_feed_opened(self) -> bool: - return len(self.driver.find_elements(*self.FEED_HEADER)) > 0 + return self.count_elements(self.FEED_HEADER) > 0 + + # ---------- модалка ---------- @allure.step("Открыть модальное окно ингредиента") def open_ingredient_modal(self): - self.wait.until( - EC.element_to_be_clickable(self.INGREDIENT) - ).click() - - self.wait.until( - EC.visibility_of_element_located(self.MODAL) - ) - - @allure.step("Проверить, что модальное окно ингредиента открыто") - def is_ingredient_modal_opened(self) -> bool: - elements = self.driver.find_elements(*self.MODAL) - return len(elements) > 0 and elements[0].is_displayed() + self.click(self.INGREDIENT) + self.wait_visible(self.MODAL) @allure.step("Закрыть модальное окно ингредиента") def close_ingredient_modal(self): @@ -69,20 +63,16 @@ def close_ingredient_modal(self): @allure.step("Дождаться закрытия модального окна") def wait_modal_closed(self): - self.wait.until( - EC.invisibility_of_element_located(self.MODAL) - ) + self.wait_invisible(self.MODAL) + + # ---------- конструктор ---------- @allure.step("Добавить ингредиент в конструктор") def add_ingredient_to_constructor(self): - ingredient = self.wait.until( - EC.presence_of_element_located(self.INGREDIENT) - ) - target = self.wait.until( - EC.presence_of_element_located(self.CONSTRUCTOR_SECTION) - ) + ingredient = self.wait_present(self.INGREDIENT) + target = self.wait_present(self.CONSTRUCTOR_SECTION) - self.driver.execute_script( + self.execute_js( """ const source = arguments[0]; const target = arguments[1]; @@ -99,4 +89,4 @@ def add_ingredient_to_constructor(self): @allure.step("Проверить, что в конструкторе есть ингредиенты") def constructor_has_items(self) -> bool: - return len(self.driver.find_elements(*self.CONSTRUCTOR_ITEMS)) > 0 + return self.count_elements(self.CONSTRUCTOR_ITEMS) > 0 diff --git a/3_task/tests/test_feed.py b/3_task/tests/test_feed.py index 7c7f1cdd1..2f0d9ff5a 100644 --- a/3_task/tests/test_feed.py +++ b/3_task/tests/test_feed.py @@ -1,72 +1,53 @@ import allure -import requests from pages.feed_page import FeedPage from pages.main_page import MainPage -BASE_URL = "https://stellarburgers.education-services.ru" - @allure.feature("Лента заказов") class TestFeed: - @allure.title("Счётчики заказов увеличиваются после оформления заказа") - def test_orders_counters(self, driver): + @allure.title("Отображение и обновление счётчиков заказов в ленте") + def test_orders_counters_display_and_update(self, driver): main_page = MainPage(driver) feed_page = FeedPage(driver) + with allure.step("Переход в конструктор"): + main_page.open_constructor() + + with allure.step("Добавление ингредиента в конструктор"): + main_page.add_ingredient_to_constructor() + assert main_page.constructor_has_items() + with allure.step("Переход в ленту заказов"): main_page.open_feed() with allure.step("Фиксация текущих значений счётчиков"): total_before = feed_page.get_total_orders() - today_before = feed_page.get_today_orders() - - with allure.step("Получение ингредиентов"): - ingredients = requests.get( - f"{BASE_URL}/api/ingredients" - ).json()["data"] - - ingredient_ids = [ingredients[0]["_id"]] - - with allure.step("Оформление заказа через API"): - response = requests.post( - f"{BASE_URL}/api/orders", - json={"ingredients": ingredient_ids} - ) - assert response.status_code == 200 with allure.step("Обновление ленты заказов"): feed_page.refresh_feed() - with allure.step("Проверка обновления счётчиков"): + with allure.step("Проверка, что счётчик выполненных заказов не уменьшился"): assert feed_page.get_total_orders() >= total_before - assert feed_page.get_today_orders() >= 0 - @allure.title("Заказ отображается в разделе «В работе»") - def test_order_in_progress(self, driver): + @allure.title("В ленте заказов отображается раздел «В работе»") + def test_orders_in_progress_section_displayed(self, driver): main_page = MainPage(driver) feed_page = FeedPage(driver) - with allure.step("Переход в ленту заказов"): - main_page.open_feed() - - with allure.step("Получение ингредиентов"): - ingredients = requests.get( - f"{BASE_URL}/api/ingredients" - ).json()["data"] + with allure.step("Переход в конструктор"): + main_page.open_constructor() - ingredient_ids = [ingredients[0]["_id"]] + with allure.step("Добавление ингредиента в конструктор"): + main_page.add_ingredient_to_constructor() + assert main_page.constructor_has_items() - with allure.step("Создание заказа"): - response = requests.post( - f"{BASE_URL}/api/orders", - json={"ingredients": ingredient_ids} - ) - assert response.status_code == 200 + with allure.step("Переход в ленту заказов"): + main_page.open_feed() - with allure.step("Обновление ленты"): + with allure.step("Обновление ленты заказов"): feed_page.refresh_feed() - with allure.step("Проверка наличия заказов в работе"): + with allure.step("Проверка наличия раздела «В работе»"): assert feed_page.has_orders_in_progress() diff --git a/3_task/tests/test_main_functional.py b/3_task/tests/test_main_functional.py index 3648649a9..4224f7bd6 100644 --- a/3_task/tests/test_main_functional.py +++ b/3_task/tests/test_main_functional.py @@ -6,41 +6,37 @@ @allure.feature("Главная страница") class TestMainFunctional: - @allure.title("Переход по клику на «Конструктор»") + @allure.title("Переход по клику на вкладку «Конструктор»") def test_open_constructor(self, driver): main_page = MainPage(driver) with allure.step("Клик по вкладке «Конструктор»"): main_page.open_constructor() - with allure.step("Проверка, что конструктор открыт"): + with allure.step("Проверка открытия конструктора"): assert main_page.is_constructor_opened() - @allure.title("Переход по клику на «Лента заказов»") + @allure.title("Переход по клику на вкладку «Лента заказов»") def test_open_feed(self, driver): main_page = MainPage(driver) with allure.step("Клик по вкладке «Лента заказов»"): main_page.open_feed() - with allure.step("Проверка, что открыта лента заказов"): + with allure.step("Проверка открытия ленты заказов"): assert main_page.is_feed_opened() @allure.title("Открытие и закрытие модального окна ингредиента") - def test_ingredient_modal(self, driver): + def test_ingredient_modal_open_and_close(self, driver): main_page = MainPage(driver) with allure.step("Открытие модального окна ингредиента"): main_page.open_ingredient_modal() - assert main_page.is_ingredient_modal_opened() with allure.step("Закрытие модального окна ингредиента"): main_page.close_ingredient_modal() main_page.wait_modal_closed() - with allure.step("Проверка, что модальное окно закрыто"): - assert not main_page.is_ingredient_modal_opened() - @allure.title("Ингредиент добавляется в конструктор") def test_ingredient_added_to_constructor(self, driver): main_page = MainPage(driver) @@ -48,5 +44,5 @@ def test_ingredient_added_to_constructor(self, driver): with allure.step("Добавление ингредиента в конструктор"): main_page.add_ingredient_to_constructor() - with allure.step("Проверка, что в конструкторе появился ингредиент"): + with allure.step("Проверка наличия ингредиента в конструкторе"): assert main_page.constructor_has_items()