File size: 5,680 Bytes
34b54ad | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 | import json
import os
import sys
import time
from datetime import datetime, timedelta
from pathlib import Path
from playwright.sync_api import sync_playwright
from backend.security import auth
# Generate admin JWT
token = auth.create_access_token(data={"sub": "master", "role": "admin"})
artifacts_dir = Path(r"C:\Users\rcnai\.gemini\antigravity-ide\brain\687690db-36e3-42ea-89a5-947c15851521")
screenshot1_path = str(artifacts_dir / "schedule_modal_conflict.png")
screenshot2_path = str(artifacts_dir / "schedule_list_conflicts.png")
with sync_playwright() as p:
browser = p.chromium.launch(headless=True)
context = browser.new_context(viewport={"width": 1280, "height": 800})
page = context.new_page()
print("[1] Navigating to http://localhost:8000/...")
page.goto("http://localhost:8000/")
page.wait_for_load_state("networkidle")
# Set JWT in localStorage and reload
print("[2] Injecting auth token...")
page.evaluate(f"localStorage.setItem('pabot_jwt', '{token}');")
page.reload()
page.wait_for_load_state("networkidle")
time.sleep(1)
# Check if auth shield is hidden
shield_display = page.evaluate("document.getElementById('authShield').style.display")
print(f"Auth shield display: {shield_display}")
# Navigate to Schedule page
print("[3] Switching to Schedule tab...")
page.click("button:has-text('Schedule')")
time.sleep(1)
# Check current schedule view state
init_html = page.inner_text("#schedEventsList")
print(f"Initial Schedule List:\n{init_html.strip()}\n")
# Click "+ New Event"
print("[4] Clicking '+ New Event'...")
page.click("button:has-text('New Event')")
page.wait_for_selector("#calendarEventModal.show", state="visible")
# Today's date in local YYYY-MM-DD
now = datetime.now()
start_dt = now.replace(minute=0, second=0, microsecond=0) + timedelta(hours=1)
end_dt = start_dt + timedelta(hours=1)
start_str = start_dt.strftime("%Y-%m-%dT%H:%M")
end_str = end_dt.strftime("%Y-%m-%dT%H:%M")
print(f"[5] Filling Event 1: 'Sprint Architecture Sync' from {start_str} to {end_str}...")
page.fill("#eventModalTitleInput", "Sprint Architecture Sync")
page.fill("#eventModalStartInput", start_str)
page.fill("#eventModalEndInput", end_str)
page.select_option("#eventModalCategoryInput", "work")
# Submit Event 1
page.click("#calendarEventModal button[type='submit']")
page.wait_for_selector("#calendarEventModal", state="hidden")
time.sleep(1.5)
# Verify Event 1 appears in the list
list_text_1 = page.inner_text("#schedEventsList")
print(f"[6] Events List after adding Event 1:\n{list_text_1.strip()}\n")
assert "Sprint Architecture Sync" in list_text_1, "Event 1 did not appear in the list!"
assert "No events scheduled for this period" not in list_text_1, "Still showing 'No events scheduled'!"
# Create Event 2: Overlapping event
print("[7] Clicking '+ New Event' for second overlapping event...")
page.click("button:has-text('New Event')")
page.wait_for_selector("#calendarEventModal.show", state="visible")
# Overlapping slot: starts 30 mins after Event 1 starts
overlap_start_dt = start_dt + timedelta(minutes=30)
overlap_end_dt = overlap_start_dt + timedelta(hours=1)
overlap_start_str = overlap_start_dt.strftime("%Y-%m-%dT%H:%M")
overlap_end_str = overlap_end_dt.strftime("%Y-%m-%dT%H:%M")
print(f"[8] Filling Event 2: 'Emergency Client Sync' from {overlap_start_str} to {overlap_end_str}...")
page.fill("#eventModalTitleInput", "Emergency Client Sync")
page.fill("#eventModalStartInput", overlap_start_str)
page.fill("#eventModalEndInput", overlap_end_str)
# Trigger input change and conflict check
page.evaluate("checkModalEventConflict();")
time.sleep(1)
# Check modal conflict banner
modal_conflict_style = page.evaluate("document.getElementById('modalConflictAlert').style.display")
modal_conflict_text = page.inner_text("#modalConflictText")
print(f"[9] Modal Conflict Alert Display: {modal_conflict_style}")
print(f" Modal Conflict Alert Text: '{modal_conflict_text}'")
# Take screenshot of modal with conflict warning
page.screenshot(path=screenshot1_path)
print(f" Saved screenshot to {screenshot1_path}")
# Submit Event 2
print("[10] Submitting overlapping event...")
page.click("#calendarEventModal button[type='submit']")
page.wait_for_selector("#calendarEventModal", state="hidden")
time.sleep(1.5)
# Verify both events and global conflict banner on schedule page
list_text_2 = page.inner_text("#schedEventsList")
global_conflict_display = page.evaluate("document.getElementById('schedGlobalConflictBanner').style.display")
global_conflict_text = page.inner_text("#schedGlobalConflictBanner")
print(f"[11] Events List after adding Overlapping Event 2:\n{list_text_2.strip()}\n")
print(f"[12] Global Conflict Banner Display: {global_conflict_display}")
print(f" Global Conflict Banner Text: '{global_conflict_text.strip()}'")
# Check conflict cards and pills
conflict_cards_count = page.evaluate("document.querySelectorAll('.sched-event-card.has-conflict').length")
conflict_pills_count = page.evaluate("document.querySelectorAll('.pill.rose').length")
print(f"[13] Conflict Cards Count: {conflict_cards_count}")
print(f" Conflict Pills Count: {conflict_pills_count}")
page.screenshot(path=screenshot2_path)
print(f" Saved screenshot to {screenshot2_path}")
browser.close()
print("\n=== SCHEDULE & CONFLICT TEST COMPLETED SUCCESSFULLY ===")
|