File SeleniumASTVisitor.cpp

File List > ast > SeleniumASTVisitor.cpp

Go to the documentation of this file

#include "SeleniumASTVisitor.h"
#include <sstream>

string SeleniumASTVisitor::visit(const VisitNode &node) {
    stringstream ss;
    ss << "await driver.get('" << node.get_url() << "');" << std::endl;
    return ss.str();
}

string SeleniumASTVisitor::visit(const ClickNode &node) {
    stringstream ss;
    ss << "await clickNode(driver, '" << node.get_description() << "', '" << node.get_element_type() << "');" << std::endl;
    return ss.str();
}

string SeleniumASTVisitor::visit(const TypeNode &node) {
    stringstream ss;
    ss << "await typeNode(driver, '" << node.get_description() << "', '" << node.get_content() << "', '" << node.get_element_type() << "');" << std::endl;
    return ss.str();
}

string SeleniumASTVisitor::visit(const CheckNode &node) {
    stringstream ss;
    string state = (node.get_state() ? "true" : "false");
    ss << "assert.equal(await checkNode(driver, '" << node.get_element_type() << "', '" << node.get_description() << "', " << state << ", title), " << state  << ");" << std::endl;
    return ss.str();
}

string SeleniumASTVisitor::visit(const TestNode &node) {
    stringstream ss;

    ss  << "it('"
        << node.testName
        << "', async function () {" << std::endl
        << "const title = '" << node.testName << "';"
        << std::endl;

    for(auto& action : node.actions) {
        ss << action->accept(*this);
    }

    ss  << "});" << std::endl;

    return ss.str();
}

string SeleniumASTVisitor::visit(const AST &tree) {
    stringstream ss;

    ss << init_hooks();

    if(!keep_xpath) { ss << get_coordinates() << element_from_point(); }

    if(keep_xpath) {        // with xpath
        ss << generate_xpath_helper();
    } else {                // with NL description
        ss << generate_seeclick_helper();
    }

    ss << generate_init();

    for(auto& test : tree.tests) {
        ss << test.accept(*this);
    }

    ss << end();

    return ss.str();
}

string SeleniumASTVisitor::generate_xpath_helper() {
    stringstream ss;
    ss << R"(
async function clickNode(driver, description, element_type) {
    const element = await driver.findElement(By.xpath(description));
    await element.click();
})" << std::endl;

    ss << R"(
async function typeNode(driver, description, content, element_type) {
    const element = await driver.findElement(By.xpath(description));
    await element.sendKeys(content);
})" << std::endl;

    ss << R"(
async function checkNode(driver, element_type, description, state, test) {
    const element = await driver.findElement(By.xpath(description));
    let isDisplayed = await element.isDisplayed();
    await afterEachAssertHook(`${element_type} with description "${description}" should be ${state ? 'displayed' : 'hidden'}`, isDisplayed == state, test);
    return isDisplayed;
})" << std::endl;
    return ss.str();
}

string SeleniumASTVisitor::generate_seeclick_helper() {
    stringstream ss;

    ss << R"(
async function clickNode(driver, description, element_type) {
    const [x, y] = await getCoordinates(driver, description, element_type);
    const actions = driver.actions({ async: true });
    await actions.move({ x, y }).click().perform();
})" << std::endl;

    ss << R"(
async function typeNode(driver, description, content, element_type) {
    const [x, y] = await getCoordinates(driver, description, element_type);
    const actions = driver.actions({ async: true });
    await actions.move({ x, y }).click().sendKeys(content).perform();
})" << std::endl;

    ss << R"(
async function checkNode(driver, element_type, description, state, test) {
    const [x, y] = await getCoordinates(driver, description, element_type);
    let element = await elementFromPoint(driver, x, y);
    let isDisplayed = await element.isDisplayed();
    await afterEachAssertHook(`${element_type} with description "${description}" should be ${state ? 'displayed' : 'hidden'}`, isDisplayed == state, test);
    return isDisplayed;
})" << std::endl;

    return ss.str();
}

string SeleniumASTVisitor::generate_init() {
    stringstream ss;

    ss  << R"(describe("Script", function () {
  let driver;
  this.timeout(0);

  before(beforeHook);
  beforeEach(beforeEachHook);
  after(afterHook);
  afterEach(afterEachHook);

  before(async function () {
    driver = await new Builder().forBrowser(Browser.CHROME)
        .setChromeOptions(new chrome.Options().addArguments("--window-size=1920,1080"))
        .build();
    await driver
      .manage()
      .setTimeouts({ implicit: 2147483647, pageLoad: 2147483647 });
  });

  after(async () => {
    await driver.quit();
  });)"
        << std::endl;

    return ss.str();
}

string SeleniumASTVisitor::element_from_point() {
    stringstream ss;
    ss << R"(async function elementFromPoint(driver, x, y) {
      return await driver.executeScript(
        "return document.elementFromPoint(arguments[0], arguments[1]);",
        x,
        y
      );
    })" << std::endl;
    return ss.str();
}

string SeleniumASTVisitor::get_coordinates() {
    stringstream ss;

    ss << R"(async function getCoordinates(driver, description, element_type) {
        try {
            const res = await fetch(getServerURL(), {
                method: "POST",
                headers: {
                    "Content-Type": "application/json",
                    "Authorization": `Bearer ${getToken()}`
                },
                body: JSON.stringify({
                    image: await driver.takeScreenshot(),
                    description: description,
                    element_type: element_type
                }),
            });

            const data = await res.json();

            if (res.ok) {
                return data;
            } else {
                throw new Error("Error in fetching coordinates");
            }
        } catch (error) {
            throw new Error("Error in fetching coordinates");
        }
    })" << std::endl;

    return ss.str();
}

string SeleniumASTVisitor::init_hooks() {
    stringstream ss;

    ss  << "const { Builder, Browser, By } = require('selenium-webdriver');"                << std::endl;
    ss  << "const assert = require('assert');"                                              << std::endl;
    ss  << "const chrome = require(\"selenium-webdriver/chrome\");"                         << std::endl;

    ss  << "function beforeHook() {}"                                                   << std::endl;
    ss  << "function beforeEachHook() {}"                                               << std::endl;
    ss  << "function afterHook() {}"                                                    << std::endl;
    ss  << "function afterEachHook() {}"                                                << std::endl;
    ss  << "function afterEachAssertHook() {}"                                              << std::endl;
    ss  << "function getToken() {}"                                                         << std::endl;
    ss  << "function getServerURL() {}"                                                     << std::endl;

    return ss.str();
}

string SeleniumASTVisitor::end() {
    stringstream ss;
    ss  << "});\n";
    return ss.str();
}