I'm trying to write a bot using Selenium Python to play an online game of tic-tac-toe. I've scraped the XPATHS of the squares and placed them in variables. The bot is simple. It's just supposed to click random squares. I'll enhance the bot later. Right now, I just want to click elements, and I'm getting stuck by this line of code:
squares[random_square].click()
I get an attribute error in the traceback. I understand strings can't invoke the click() method, and usually, I would have something like this:
pickSquare = WebDriverWait(load_browser, 10).until(EC.element_to_be_clickable(By.XPATH, Tags.someSquare))
pickSquare.click()
But I've put all of my XPATH variables into an array that I need to iterate through, and I'm not sure how to use By and EC on an array as such. Below is the code I have so far.
import pytest
import time
import logging
from random import randint
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
LOGGER = logging.getLogger(__name__)
class Tags():
square1 = "(//div[contains(@class, 'board-row')]//button[contains(@class, 'square')])[1]"
square2 = "(//div[contains(@class, 'board-row')]//button[contains(@class, 'square')])[2]"
square3 = "(//div[contains(@class, 'board-row')]//button[contains(@class, 'square')])[3]"
square4 = "(//div[contains(@class, 'board-row')]//button[contains(@class, 'square')])[4]"
square5 = "(//div[contains(@class, 'board-row')]//button[contains(@class, 'square')])[5]"
square6 = "(//div[contains(@class, 'board-row')]//button[contains(@class, 'square')])[6]"
square7 = "(//div[contains(@class, 'board-row')]//button[contains(@class, 'square')])[7]"
square8 = "(//div[contains(@class, 'board-row')]//button[contains(@class, 'square')])[8]"
square9 = "(//div[contains(@class, 'board-row')]//button[contains(@class, 'square')])[9]"
resultOh = "//div[contains(@class, 'game-info')]//div[contains(text(), 'Winner: O')]"
resultEx = "//div[contains(@class, 'game-info')]//div[contains(text(), 'Winner: X')]"
resultTie = "//div[contains(@class, 'game-info')]//div[contains(text(), 'tie')]"
class TestCase_PlayTTT():
URL = "http://localhost:3000"
@pytest.fixture
def load_browser(self, browser):
browser.get(self.URL)
yield browser
def test_playTTT(self, load_browser):
squares = [Tags.square1,Tags.square2,Tags.square3,
Tags.square4,Tags.square5,Tags.square6,
Tags.square7,Tags.square8,Tags.square9]
clickedSquares = []
random_square = randint(0,8)
time.sleep(10)
for i in clickedSquares:
if i == random_square:
self.test_playTTT()
else:
clickedSquares.append(random_square)
squares[random_square].click()
if WebDriverWait(load_browser, 10).until(EC.presence_of_element_located(By.XPATH, Tags.resultOh)):
winner = 'O'
LOGGER.info('Winner O')
assert winner
elif WebDriverWait(load_browser, 10).until(EC.presence_of_element_located(By.XPATH, Tags.resultEx)):
winner = 'X'
LOGGER.info('Winner X')
assert winner
else:
winner = 'Tie'
LOGGER.info('Tie')
assert winner
UPDATE 1: Below is the traceback.
self = <TestCases.TestCase_PlayTTT.TestCase_PlayTTT object at 0x000001DA3F4139D0>
load_browser = <selenium.webdriver.firefox.webdriver.WebDriver (session="324ff7dc-195c-4bdf-9ceb-84bf978dfc66")>
def test_playTTT(self, load_browser):
squares = [Tags.square1,Tags.square2,Tags.square3,
Tags.square4,Tags.square5,Tags.square6,
Tags.square7,Tags.square8,Tags.square9]
clickedSquares = []
random_square = randint(0,8)
time.sleep(10)
for i in clickedSquares:
if i == random_square:
self.test_playTTT()
else:
clickedSquares.append(random_square)
> squares[random_square].click()
E AttributeError: 'str' object has no attribute 'click'
TestCases\TestCase_PlayTTT.py:52: AttributeError
CodePudding user response:
You are missing a pair of parenthesis in expression.
Instead of
WebDriverWait(load_browser, 10).until(EC.presence_of_element_located(By.XPATH, Tags.resultOh))
And
WebDriverWait(load_browser, 10).until(EC.presence_of_element_located(By.XPATH, Tags.resultEx))
Try
WebDriverWait(load_browser, 10).until((EC.presence_of_element_located(By.XPATH, Tags.resultOh)))
And
WebDriverWait(load_browser, 10).until((EC.presence_of_element_located(By.XPATH, Tags.resultEx)))
CodePudding user response:
I think you may need to restructure your code to do something like this to get the right objects to use click() on an element:
# import webdriver
from selenium import webdriver
# create webdriver object
driver = webdriver.Firefox()
# get geeksforgeeks.org
driver.get("http://localhost:3000/")
then have the code that loops waiting on on results and selecting the next thing to try and when you are ready to find and click the element have code like this:
# get element
element = driver.find_element(By.XPATH, squares[random_square])
# click the element
element.click()