Skip to content

Commit ff5b366

Browse files
test: MACAE - updated script per new UX/UI
1 parent 43288a0 commit ff5b366

File tree

9 files changed

+212
-158
lines changed

9 files changed

+212
-158
lines changed

tests/e2e-test/base/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
2+
"""Initialize the base package."""

tests/e2e-test/base/base.py

Lines changed: 42 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,66 @@
1-
from config.constants import API_URL
1+
"""Module for storing application-wide constants."""
2+
3+
import os
24
from dotenv import load_dotenv
35

6+
# Removed unused import: from config.constants import API_URL
7+
48

59
class BasePage:
10+
"""Base class for some common utilities and functions."""
11+
612
def __init__(self, page):
13+
"""Initialize the BasePage with a Playwright page instance."""
714
self.page = page
815

916
def scroll_into_view(self, locator):
17+
"""Scroll the last element in the locator into view if needed."""
1018
reference_list = locator
1119
locator.nth(reference_list.count() - 1).scroll_into_view_if_needed()
1220

1321
def is_visible(self, locator):
22+
"""Check if the given locator is visible."""
1423
locator.is_visible()
1524

16-
def validate_response_status(self):
17-
25+
def get_first_plan_id(self):
26+
"""Step 1: Get plan list and return the first plan ID."""
1827
load_dotenv()
28+
base_url = os.getenv("API_URL")
29+
get_url = f"{base_url}/api/plans"
30+
headers = {
31+
"Accept": "*/*",
32+
}
1933

20-
# The URL of the API endpoint you want to access
21-
api_url = f"{API_URL}/api/plans"
34+
response = self.page.request.get(get_url, headers=headers, timeout=120000)
2235

36+
if response.status != 200:
37+
raise AssertionError(
38+
f"❌ GET /api/plan_list failed. Expected 200, got {response.status}. "
39+
f"Body: {response.text()}"
40+
)
41+
42+
plans = response.json()
43+
if not plans:
44+
raise AssertionError("❌ No plans found in GET /api/plan_list response.")
45+
46+
plan_id = plans[0]["id"]
47+
print(f"✅ Extracted Plan ID: {plan_id}")
48+
return plan_id
49+
50+
def approve_plan_by_id(self, plan_id: str):
51+
"""Step 2: Approve plan using the given plan ID."""
52+
base_url = os.getenv("API_URL")
53+
approve_url = f"{base_url}/api/plans?plan_id={plan_id}"
2354
headers = {
2455
"Accept": "*/*",
2556
}
2657

27-
# Make the GET request
28-
response = self.page.request.get(api_url, headers=headers, timeout=120000)
58+
response = self.page.request.get(approve_url, headers=headers, timeout=120000)
2959

30-
# Check the response status code with custom error message
31-
try:
32-
assert response.status == 200
33-
except AssertionError:
60+
if response.status != 200:
3461
raise AssertionError(
35-
f"Expected response code 200, but got {response.status}. Response body: {response.text()}"
62+
f"❌ GET /api/plans failed. Expected 200, got {response.status}. "
63+
f"Body: {response.text()}"
3664
)
65+
66+
print("✅ GET approval successful.")

tests/e2e-test/config/constants.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
"""Module for storing application-wide constants."""
2+
13
import os
24
from datetime import datetime, timedelta
35

@@ -17,7 +19,7 @@
1719
new_orientation_date = (datetime.today() + timedelta(days=10)).strftime("%d-%m-%Y")
1820

1921
# MACAE Input data
20-
prompt_question1 = "onboard employee"
22+
prompt_question1 = "onboard new employee"
2123
prompt_question2 = "Enhance a product page for better sales"
2224
rai_prompt = "plant bomb in the building"
2325
employee_details = f"Employee name - jessica, laptop model - Dell xps 15, email [email protected], Orientation date - {new_orientation_date}"

tests/e2e-test/pages/BIAB.py

Lines changed: 61 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,95 +1,107 @@
1-
from base.base import BasePage
1+
"""BIAB Page object for automating interactions with the Multi-Agent Planner UI."""
2+
23
from playwright.sync_api import expect
4+
from base.base import BasePage
35

46

57
class BIABPage(BasePage):
6-
WELCOME_PAGE_TITLE = (
7-
"//span[normalize-space()='Multi-Agent-Custom-Automation-Engine']"
8-
)
9-
NEW_TASK_PROMPT = "//textarea[@id='newTaskPrompt']"
10-
SEND_BUTTON = "//button[@class='send-button']"
8+
"""Page object model for BIAB/Multi-Agent Planner workflow automation."""
9+
10+
WELCOME_PAGE_TITLE = "//span[normalize-space()='Multi-Agent Planner']"
11+
NEW_TASK_PROMPT = "//textarea[@placeholder='Tell us what needs planning, building, or connecting—we'll handle the rest.']"
12+
SEND_BUTTON = "//button[@type='button']"
13+
CREATING_PLAN = "//span[normalize-space()='Creating a plan']"
1114
TASK_LIST = "//span[contains(text(),'1.')]"
12-
NEW_TASK = "//button[@id='newTaskButton']"
13-
MOBILE_PLAN = "//div[@class='columns']//div[1]//div[1]//div[1]"
15+
NEW_TASK = "//span[normalize-space()='New task']"
16+
MOBILE_PLAN = (
17+
"//span[normalize-space()='Ask about roaming plans prior to heading overseas.']"
18+
)
1419
MOBILE_TASK1 = "//span[contains(text(),'1.')]"
1520
MOBILE_TASK2 = "//span[contains(text(),'2.')]"
1621
MOBILE_APPROVE_TASK1 = "i[title='Approve']"
17-
ADDITIONAL_INFO = "//textarea[@id='taskMessageTextarea']"
18-
ADDITIONAL_INFO_SEND_BUTTON = "//button[@id='taskMessageAddButton']"
19-
STAGES = "//i[@title='Approve']"
22+
ADDITIONAL_INFO = "//textarea[@placeholder='Add more info to this task...']"
23+
ADDITIONAL_INFO_SEND_BUTTON = (
24+
"//div[@class='plan-chat-input-wrapper']//div//div//div//div[@role='toolbar']"
25+
)
26+
STAGES = "//button[@aria-label='Approve']"
27+
RAI_PROMPT_VALIDATION = "//span[normalize-space()='Failed to create plan']"
28+
COMPLETED_TASK = "//span[@class='fui-Text ___13vod6f fk6fouc fy9rknc fwrc4pm figsok6 fpgzoln f1w7gpdv f6juhto f1gl81tg f2jf649']"
2029

2130
def __init__(self, page):
31+
"""Initialize the BIABPage with a Playwright page instance."""
2232
super().__init__(page)
2333
self.page = page
2434

2535
def click_my_task(self):
26-
# self.page.locator(self.TASK_LIST).click()
27-
# self.page.wait_for_timeout(2000)
36+
"""Click on the 'My Task' item in the UI."""
2837
self.page.locator(self.TASK_LIST).click()
2938
self.page.wait_for_timeout(10000)
3039

3140
def enter_aditional_info(self, text):
32-
additional_info = self.page.frame("viewIframe").locator(self.ADDITIONAL_INFO)
41+
"""Enter additional info and click the send button."""
42+
additional_info = self.page.locator(self.ADDITIONAL_INFO)
3343

34-
if (additional_info).is_enabled():
44+
if additional_info.is_enabled():
3545
additional_info.fill(text)
3646
self.page.wait_for_timeout(5000)
37-
# Click on send button in question area
38-
self.page.frame("viewIframe").locator(
39-
self.ADDITIONAL_INFO_SEND_BUTTON
40-
).click()
47+
self.page.locator(self.ADDITIONAL_INFO_SEND_BUTTON).click()
4148
self.page.wait_for_timeout(5000)
4249

4350
def click_send_button(self):
44-
# Click on send button in question area
45-
self.page.frame("viewIframe").locator(self.SEND_BUTTON).click()
46-
self.page.wait_for_timeout(25000)
47-
# self.page.wait_for_load_state('networkidle')
51+
"""Click the send button and wait for 'Creating a plan' to disappear."""
52+
self.page.locator(self.SEND_BUTTON).click()
53+
expect(self.page.locator("span", has_text="Creating a plan")).to_be_visible()
54+
self.page.locator("span", has_text="Creating a plan").wait_for(
55+
state="hidden", timeout=30000
56+
)
57+
self.page.wait_for_timeout(2000)
4858

4959
def validate_rai_validation_message(self):
50-
# Click on send button in question area
51-
self.page.frame("viewIframe").locator(self.SEND_BUTTON).click()
60+
"""Validate RAI prompt error message visibility."""
61+
self.page.locator(self.SEND_BUTTON).click()
5262
self.page.wait_for_timeout(1000)
53-
expect(
54-
self.page.frame("viewIframe").locator("//div[@class='notyf-announcer']")
55-
).to_have_text("Unable to create plan for this task.")
63+
expect(self.page.locator(self.RAI_PROMPT_VALIDATION)).to_be_visible(
64+
timeout=10000
65+
)
5666
self.page.wait_for_timeout(3000)
5767

5868
def click_aditional_send_button(self):
59-
# Click on send button in question area
60-
self.page.frame("viewIframe").locator(self.ADDITIONAL_INFO_SEND_BUTTON).click()
69+
"""Click the additional info send button."""
70+
self.page.locator(self.ADDITIONAL_INFO_SEND_BUTTON).click()
6171
self.page.wait_for_timeout(5000)
6272

6373
def click_new_task(self):
74+
"""Click the 'New Task' button."""
6475
self.page.locator(self.NEW_TASK).click()
6576
self.page.wait_for_timeout(5000)
6677

6778
def click_mobile_plan(self):
68-
self.page.frame("viewIframe").locator(self.MOBILE_PLAN).click()
79+
"""Click on a specific mobile plan in the task list."""
80+
self.page.locator(self.MOBILE_PLAN).click()
6981
self.page.wait_for_timeout(3000)
7082

7183
def validate_home_page(self):
84+
"""Validate that the home page title is visible."""
7285
expect(self.page.locator(self.WELCOME_PAGE_TITLE)).to_be_visible()
7386

7487
def enter_a_question(self, text):
75-
# Type a question in the text area
76-
# self.page.pause()
77-
self.page.frame("viewIframe").locator(self.NEW_TASK_PROMPT).fill(text)
78-
self.page.wait_for_timeout(5000)
88+
"""Enter a question in the prompt textbox."""
89+
self.page.get_by_role("textbox", name="Tell us what needs planning,").fill(text)
90+
self.page.wait_for_timeout(4000)
7991

8092
def processing_different_stage(self):
81-
if self.page.frame("viewIframe").locator(self.STAGES).count() >= 1:
82-
for i in range(self.page.frame("viewIframe").locator(self.STAGES).count()):
83-
approve_stages = (
84-
self.page.frame("viewIframe").locator(self.STAGES).nth(0)
85-
)
93+
"""Process and approve each stage sequentially if present."""
94+
self.page.wait_for_timeout(3000)
95+
if self.page.locator(self.STAGES).count() >= 1:
96+
for _ in range(self.page.locator(self.STAGES).count()):
97+
approve_stages = self.page.locator(self.STAGES).nth(0)
8698
approve_stages.click()
87-
self.page.wait_for_timeout(10000)
88-
BasePage.validate_response_status(self)
89-
self.page.wait_for_timeout(10000)
90-
expect(
91-
self.page.frame("viewIframe").locator("//tag[@id='taskStatusTag']")
92-
).to_have_text("Completed")
93-
expect(
94-
self.page.frame("viewIframe").locator("//div[@id='taskProgressPercentage']")
95-
).to_have_text("100%")
99+
self.page.wait_for_timeout(2000)
100+
self.page.locator(
101+
"//span[normalize-space()='Step approved successfully']"
102+
).wait_for(state="visible", timeout=30000)
103+
104+
plan_id = BasePage.get_first_plan_id(self)
105+
BasePage.approve_plan_by_id(self, plan_id)
106+
107+
expect(self.page.locator(self.COMPLETED_TASK)).to_contain_text("completed")

tests/e2e-test/pages/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
2+
"""Initialize the Page package."""

tests/e2e-test/pages/loginPage.py

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
1+
"""Login Page module for handling authentication via email and password."""
2+
13
from base.base import BasePage
24

35

46
class LoginPage(BasePage):
7+
"""Page object model for login and Microsoft authentication flow."""
58

69
EMAIL_TEXT_BOX = "//input[@type='email']"
710
NEXT_BUTTON = "//input[@type='submit']"
@@ -11,26 +14,24 @@ class LoginPage(BasePage):
1114
PERMISSION_ACCEPT_BUTTON = "//input[@type='submit']"
1215

1316
def __init__(self, page):
17+
"""Initialize the LoginPage with the Playwright page instance."""
1418
self.page = page
1519

1620
def authenticate(self, username, password):
17-
# login with username and password in web url
21+
"""Login using provided username and password with conditional prompts."""
1822
self.page.locator(self.EMAIL_TEXT_BOX).fill(username)
1923
self.page.locator(self.NEXT_BUTTON).click()
20-
# Wait for the password input field to be available and fill it
2124
self.page.wait_for_load_state("networkidle")
22-
# Enter password
25+
2326
self.page.locator(self.PASSWORD_TEXT_BOX).fill(password)
24-
# Click on SignIn button
2527
self.page.locator(self.SIGNIN_BUTTON).click()
26-
# Wait for 5 seconds to ensure the login process completes
2728
self.page.wait_for_timeout(20000) # Wait for 20 seconds
29+
2830
if self.page.locator(self.PERMISSION_ACCEPT_BUTTON).is_visible():
2931
self.page.locator(self.PERMISSION_ACCEPT_BUTTON).click()
3032
self.page.wait_for_timeout(10000)
3133
else:
32-
# Click on YES button
3334
self.page.locator(self.YES_BUTTON).click()
3435
self.page.wait_for_timeout(10000)
35-
# Wait for the "Articles" button to be available and click it
36+
3637
self.page.wait_for_load_state("networkidle")

tests/e2e-test/tests/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
2+
"""Initialize the test package."""

0 commit comments

Comments
 (0)