Initial commit
Dieser Commit ist enthalten in:
178
social_networks/x/x_selectors.py
Normale Datei
178
social_networks/x/x_selectors.py
Normale Datei
@ -0,0 +1,178 @@
|
||||
# social_networks/x/x_selectors.py
|
||||
|
||||
"""
|
||||
X (Twitter) Selektoren - Zentrale Sammlung aller CSS-Selektoren für X
|
||||
"""
|
||||
|
||||
class XSelectors:
|
||||
"""
|
||||
Zentrale Klasse für alle X-spezifischen CSS-Selektoren.
|
||||
Organisiert nach Funktionsbereichen.
|
||||
"""
|
||||
|
||||
# === ALLGEMEINE SELEKTOREN ===
|
||||
COOKIE_ACCEPT_BUTTONS = [
|
||||
"button:has-text('Accept all')",
|
||||
"button:has-text('Alle akzeptieren')",
|
||||
"button:has-text('Accept')",
|
||||
"button:has-text('Akzeptieren')"
|
||||
]
|
||||
|
||||
# === REGISTRIERUNG ===
|
||||
REGISTRATION = {
|
||||
# Hauptseite
|
||||
"create_account_button": 'text="Account erstellen"', # Robustester Selektor
|
||||
"create_account_button_en": 'text="Create account"', # Englische Version
|
||||
"create_account_button_alt": 'span:has-text("Account erstellen")', # Alternative
|
||||
"create_account_button_div": 'div[dir="ltr"] >> text="Account erstellen"', # Spezifischer
|
||||
|
||||
# Formularfelder
|
||||
"name_input": 'input[name="name"]',
|
||||
"email_input": 'input[name="email"]',
|
||||
"phone_input": 'input[name="phone"]',
|
||||
|
||||
# Geburtsdatum Dropdowns
|
||||
"month_select": 'select#SELECTOR_1',
|
||||
"day_select": 'select#SELECTOR_2',
|
||||
"year_select": 'select#SELECTOR_3',
|
||||
|
||||
# Buttons
|
||||
"next_button_birthday": 'button[data-testid="ocfSignupNextLink"]',
|
||||
"next_button_settings": 'button[data-testid="ocfSettingsListNextButton"]',
|
||||
"register_button": 'button[data-testid="LoginForm_Login_Button"]',
|
||||
|
||||
# Verifizierung
|
||||
"verification_code_input": 'input[autocomplete="one-time-code"]',
|
||||
"verification_code_label": 'div:has-text("Verifizierungscode")',
|
||||
|
||||
# Passwort
|
||||
"password_input": 'input[type="password"]',
|
||||
"password_label": 'div:has-text("Passwort")',
|
||||
|
||||
# Skip-Buttons
|
||||
"skip_profile_picture": 'button[data-testid="ocfSelectAvatarSkipForNowButton"]',
|
||||
"skip_username": 'button[data-testid="ocfEnterUsernameSkipButton"]',
|
||||
"skip_notifications": 'button:has-text("Vorerst überspringen")',
|
||||
"skip_for_now": 'button:has-text("Nicht jetzt")'
|
||||
}
|
||||
|
||||
# === LOGIN ===
|
||||
LOGIN = {
|
||||
# Login-Buttons
|
||||
"login_button": 'a[href="/login"]',
|
||||
"login_button_alt": 'div:has-text("Anmelden")',
|
||||
|
||||
# Formularfelder
|
||||
"username_input": 'input[autocomplete="username"]',
|
||||
"email_or_username_input": 'input[name="text"]',
|
||||
"password_input": 'input[type="password"]',
|
||||
"password_input_alt": 'input[name="password"]',
|
||||
|
||||
# Submit-Buttons
|
||||
"next_button": 'div[role="button"]:has-text("Weiter")',
|
||||
"next_button_en": 'div[role="button"]:has-text("Next")',
|
||||
"login_submit": 'div[role="button"]:has-text("Anmelden")',
|
||||
"login_submit_en": 'div[role="button"]:has-text("Log in")'
|
||||
}
|
||||
|
||||
# === NAVIGATION ===
|
||||
NAVIGATION = {
|
||||
# Hauptnavigation
|
||||
"home_link": 'a[href="/home"]',
|
||||
"explore_link": 'a[href="/explore"]',
|
||||
"notifications_link": 'a[href="/notifications"]',
|
||||
"messages_link": 'a[href="/messages"]',
|
||||
"profile_link": 'a[data-testid="AppTabBar_Profile_Link"]',
|
||||
|
||||
# Tweet/Post-Buttons
|
||||
"tweet_button": 'a[data-testid="SideNav_NewTweet_Button"]',
|
||||
"tweet_button_inline": 'button[data-testid="tweetButtonInline"]',
|
||||
|
||||
# Navigation Container
|
||||
"primary_nav": 'nav[aria-label="Primary"]',
|
||||
"sidebar": 'div[data-testid="sidebarColumn"]'
|
||||
}
|
||||
|
||||
# === PROFIL ===
|
||||
PROFILE = {
|
||||
# Profilbearbeitung
|
||||
"edit_profile_button": 'button:has-text("Profil bearbeiten")',
|
||||
"edit_profile_button_en": 'button:has-text("Edit profile")',
|
||||
|
||||
# Formularfelder
|
||||
"display_name_input": 'input[name="displayName"]',
|
||||
"bio_textarea": 'textarea[name="description"]',
|
||||
"location_input": 'input[name="location"]',
|
||||
"website_input": 'input[name="url"]',
|
||||
|
||||
# Speichern
|
||||
"save_button": 'button:has-text("Speichern")',
|
||||
"save_button_en": 'button:has-text("Save")'
|
||||
}
|
||||
|
||||
# === VERIFIZIERUNG ===
|
||||
VERIFICATION = {
|
||||
# Challenge/Captcha
|
||||
"challenge_frame": 'iframe[title="arkose-challenge"]',
|
||||
"captcha_frame": 'iframe[src*="recaptcha"]',
|
||||
|
||||
# Telefonnummer-Verifizierung
|
||||
"phone_verification_input": 'input[name="phone_number"]',
|
||||
"send_code_button": 'button:has-text("Code senden")',
|
||||
"verification_code_input": 'input[name="verification_code"]'
|
||||
}
|
||||
|
||||
# === FEHLER UND WARNUNGEN ===
|
||||
ERRORS = {
|
||||
# Fehlermeldungen
|
||||
"error_message": 'div[data-testid="toast"]',
|
||||
"error_alert": 'div[role="alert"]',
|
||||
"rate_limit_message": 'span:has-text("versuchen Sie es später")',
|
||||
"suspended_message": 'span:has-text("gesperrt")',
|
||||
|
||||
# Spezifische Fehler
|
||||
"email_taken": 'span:has-text("E-Mail-Adresse wird bereits verwendet")',
|
||||
"invalid_credentials": 'span:has-text("Falscher Benutzername oder falsches Passwort")'
|
||||
}
|
||||
|
||||
# === MODALE DIALOGE ===
|
||||
MODALS = {
|
||||
# Allgemeine Modale
|
||||
"modal_container": 'div[role="dialog"]',
|
||||
"modal_close_button": 'div[aria-label="Schließen"]',
|
||||
"modal_close_button_en": 'div[aria-label="Close"]',
|
||||
|
||||
# Bestätigungsdialoge
|
||||
"confirm_button": 'button:has-text("Bestätigen")',
|
||||
"cancel_button": 'button:has-text("Abbrechen")'
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def get_selector(cls, category: str, key: str) -> str:
|
||||
"""
|
||||
Holt einen spezifischen Selektor.
|
||||
|
||||
Args:
|
||||
category: Kategorie (z.B. "REGISTRATION", "LOGIN")
|
||||
key: Schlüssel innerhalb der Kategorie
|
||||
|
||||
Returns:
|
||||
str: CSS-Selektor oder None
|
||||
"""
|
||||
category_dict = getattr(cls, category.upper(), {})
|
||||
if isinstance(category_dict, dict):
|
||||
return category_dict.get(key)
|
||||
return None
|
||||
|
||||
@classmethod
|
||||
def get_all_selectors(cls, category: str) -> dict:
|
||||
"""
|
||||
Holt alle Selektoren einer Kategorie.
|
||||
|
||||
Args:
|
||||
category: Kategorie
|
||||
|
||||
Returns:
|
||||
dict: Alle Selektoren der Kategorie
|
||||
"""
|
||||
return getattr(cls, category.upper(), {})
|
||||
In neuem Issue referenzieren
Einen Benutzer sperren