codeceptjs / CodeceptJS

Supercharged End 2 End Testing Framework for NodeJS
http://codecept.io
MIT License
4.1k stars 723 forks source link

Question: how to add custom locators? #708

Closed masterjg closed 3 years ago

masterjg commented 7 years ago

What are you trying to achieve?

I'm trying to add new custom locator.

What do you get instead?

WebDriverError: unknown error: by is not defined (Session info: chrome=60.0.3112.78) (Driver info: chromedriver=2.32.498513 (2c63aa53b2c658de596ed550eb5267ec5967b351),platform=Linux 4.8.0-59-generic x86_64)

Provide test source code if related

Here is my custom helper to sort of add custom locator. I think there should be a better way to register new locators?

'use strict';

class CustomLocators extends codecept_helper
{
    _beforeSuite()
    {
        if (this.areLocatorsAdded === true) {
            return;
        }
        by.addLocator("text", (text, locator) => {
            return by.cssContainingText(locator, text); //here by is undefined for some reason
        });
        this.areLocatorsAdded = true;
    }
}

module.exports = CustomLocators;

Details

const BUILD_NO = process.env.BUILD_NO || "2.17.01.01-001";
const HUB_IP = process.env.HUB_IP || "localhost";
const TEST_URL = process.env.TEST_URL || "https://www.google.com";

exports.config = {
    tests: "./tests/**/*.js",
    include: {
        I: "./include/i.js",
        Authentication: "./include/page-objects/authentication.js"
    },
    timeout: 1000,
    output: "output/" + BUILD_NO,
    helpers: {
        Protractor: {
            url: TEST_URL,
            browser: "chrome",
            smartWait: 1000,
            uniqueScreenshotNames: true,
            seleniumAddress: "http://" + HUB_IP + ":4444/wd/hub",
            rootElement: "html",
            waitForTimeout: 1000,
            scriptTimeout: 1000,
            windowSize: "1366x768", //based on https://www.w3schools.com/browsers/browsers_display.asp
            capabilities: {}
        },
        Mochawesome: {
            uniqueScreenshotNames: true
        },
        CustomLocators: {
            require: "./include/helpers/custom-locators.js"
        }
    },
    mocha: {
        reporterOptions: {
            reportDir: "output/" + BUILD_NO,
            reportFilename: "acceptance_report",
            reportTitle: "Acceptance report for build " + BUILD_NO,
            reportPageTitle: "Acceptance report for build " + BUILD_NO,
            inlineAssets: true,
            autoOpen: (HUB_IP === "localhost" || HUB_IP === "127.0.0.1"),
            quiet: true
        }
    },
    multiple: {
        production: {
            browsers: [
                "chrome",
                "firefox",
                "edge",
                "ie"
            ]
        }
    },
    name: "tt2-tests"
};
DavertMik commented 7 years ago

Sorry, we don't have a way to register custom locators :( Probably after a hard refactoring, we would provide a way to do it

masterjg commented 7 years ago

Well that's too bad... Um, how do I select then by text (I know that I can do that by xpath, but that sounds more like a hack)? I thought that cssContainingText locator would work, but that too throws errors: I.click({ cssContainingText: "English" });

No element found using locator: by.cssContainingText("English", "undefined")

I expect codeception to call cssContainingText(cssSelector, searchText)

DavertMik commented 7 years ago

Well, you can easily generate such locator using XPath (it's not a hack). I'd suggest to make a function to create such locators

function el_contains(el, text) {
   return `//${el}[contains(., ${text})]`;
}
// usage
el_contains('h2', 'hello');