(code: str)
| 1518 | |
| 1519 | |
| 1520 | def parse_playwright_code(code: str) -> list[ParsedPlaywrightCode]: |
| 1521 | # extract function calls |
| 1522 | if not code.startswith("page."): |
| 1523 | raise ValueError( |
| 1524 | f'Playwright action must start with "page.", but got {code}' |
| 1525 | ) |
| 1526 | |
| 1527 | regex = r"\.(?![^\(\)]*\))" |
| 1528 | chain = re.split(regex, code)[1:] |
| 1529 | |
| 1530 | parsed_chain = [] |
| 1531 | |
| 1532 | for item in chain: |
| 1533 | tree = ast.parse(item) |
| 1534 | funcs = [] |
| 1535 | for node in ast.walk(tree): |
| 1536 | if isinstance(node, ast.Call): |
| 1537 | function_name = node.func.id # type: ignore[attr-defined] |
| 1538 | arguments = [ |
| 1539 | ast.literal_eval(arg) if isinstance(arg, ast.Str) else arg |
| 1540 | for arg in node.args |
| 1541 | ] |
| 1542 | keywords = { |
| 1543 | str(kw.arg): ast.literal_eval(kw.value) |
| 1544 | for kw in node.keywords |
| 1545 | } |
| 1546 | funcs.append( |
| 1547 | ParsedPlaywrightCode( |
| 1548 | { |
| 1549 | "function_name": function_name, |
| 1550 | "arguments": arguments, |
| 1551 | "keywords": keywords, |
| 1552 | } |
| 1553 | ) |
| 1554 | ) |
| 1555 | |
| 1556 | if len(funcs) != 1: |
| 1557 | raise ValueError(f"Fail to parse {item} in {code}") |
| 1558 | |
| 1559 | if ( |
| 1560 | funcs[0]["function_name"] |
| 1561 | not in PLAYWRIGHT_LOCATORS + PLAYWRIGHT_ACTIONS |
| 1562 | ): |
| 1563 | raise ValueError( |
| 1564 | f"Invalid playwright code {item}, ", |
| 1565 | f"the function needs to be one of {PLAYWRIGHT_LOCATORS + PLAYWRIGHT_ACTIONS}", |
| 1566 | ) |
| 1567 | |
| 1568 | parsed_chain.append(funcs[0]) |
| 1569 | |
| 1570 | last_action = parsed_chain[-1] |
| 1571 | if last_action["function_name"] not in PLAYWRIGHT_ACTIONS: |
| 1572 | raise ValueError( |
| 1573 | f"Invalid playwright action {last_action},", |
| 1574 | f"the action needs to be one of {PLAYWRIGHT_ACTIONS}", |
| 1575 | ) |
| 1576 | |
| 1577 | return parsed_chain |
no test coverage detected