npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

aft-ui-selenium

v12.1.1

Published

Automated Functional Testing (AFT) package supporting UI testing in browsers

Downloads

17

Readme

AFT-UI-SELENIUM

Automated Functional Testing (AFT) package providing Selenium-based SeleniumComponent extends UiComponent class for use with POM-based UI testing strategies as well as UiSessionGeneratorPlugin implementations for connecting to Selenium via a Grid or Locally.

Installation

> npm i aft-ui-selenium

Page Object Model (POM)

the POM is a standard design pattern used in UI and layout testing. AFT-UI-SELENIUM supports this model via Components where the Component class is an object extending from SeleniumComponent and is responsible for interacting with the UI in a structured way. For example:

aft-ui-pom

The above would use a POM design like:

Session - Selenium.WebDriver

  • Page Facet - SeleniumComponent
    • logo element - WebElement
    • Breadcrumbs Facet - SeleniumComponent
      • breadcrumb links - WebElement[]
    • avatar element - WebElement
    • Nav Facet - SeleniumComponent
      • nav elements - WebElement[]
    • Tabs Facet - SeleniumComponent
      • Tab Facet 1 - SeleniumComponent
      • Tab Facet 2 - SeleniumComponent
        • Table Facet - SeleniumComponent
          • header elements - WebElement[]
          • cell elements - WebElement[]
      • Tab Facet 3 - SeleniumComponent
    • media element - WebElement

Plugins

  • grid-session-generator-plugin: a Selenium Grid plugin used to initiate UI sessions with an existing Selenium Grid. NOTE: this will not startup a new Grid and instead expects that your Grid is already running
  • local-session-generator-plugin: a Selenium WebDriver plugin used to initiate UI sessions with specific browser drivers (i.e. ChromeDriver, GeckoDriver, etc.). NOTE: if using the LocalSessionGeneratorPlugin you may also need to include npm package references to your Browser Driver package such as ChromeDriver

Creating your own Components for use in testing

Take the following as an example of how one could interact with the following page https://the-internet.herokuapp.com/login

Step 1: create the Page Component

/**
 * represents the login page object containing widgets encapsulating
 * the functionality of the website
 */
export class HerokuLoginPage extends SeleniumComponent {
    /* the locator can also be specified in options */
    override get locator(): Locator { return By.css('html'); }
    /* components contained in this page */
    private get content() { return this.getComponent(HerokuContentComponent); }
    private get messages() { return this.getComponent(HerokuMessagesComponent); }
    async navigateTo(): Promise<void> {
        await this.driver.navigate().to('https://the-internet.herokuapp.com/login');
    }
    /* action functions */
    async login(user: string, pass: string): Promise<void> {
        await this.content.login(user, pass);
    }
    async hasMessage(): Promise<boolean> {
        return await this.messages.hasMessage();
    }
    async getMessage(): Promise<string> {
        return await this.messages.getMessage();
    }
}

Step 2: create the content and messages Facets

/**
 * represents the content of the login page including the 
 * username and password fields and the login button
 */
export class HerokuContentComponent extends SeleniumComponent {
    readonly locator: Locator = By.id("content");
    /**
     * get Component's root element (`root`) using
     * the Component.locator and then call 
     * `root.findElement(By.id("username"))` from that
     */
    private get usernameInput() { return this.getRoot().then(r => r.findElement(By.id("username"))); }
    private get passwordInput() { return this.getRoot().then(r => r.findElement(By.id("password"))); }
    private get loginButton() { return this.getRoot().then(r => r.findElement(By.css("button.radius"))); }
    /* action functions */
    async login(user: string, pass: string): Promise<void> {
        await this.usernameInput.then(input => input.sendKeys(user));
        await this.passwordInput.then(input => input.sendKeys(pass));
        return await this.clickLoginButton();
    }
    async clickLoginButton(): Promise<void> {
        await this.loginButton.then(button => button.click());
    }
}
/**
 * represents the results message content shown on successful 
 * or failed login.
 */
export class HerokuMessagesComponent extends SeleniumComponent {
    readonly locator: Locator = By.id("flash-messages");
    private get message() { return this.getRoot().then(r => r.findElement(By.id("flash")); }
    /* action functions */
    async hasMessage(): Promise<boolean> {
        return await this.message
            .then((message) => {
                return message !== undefined;
            }).catch((err: Error) => {
                return false;
            });
    }
    async getMessage(): Promise<string> {
        if (await this.hasMessage()) {
            return await this.message.then(m => m.getText());
        }
        return null;
    }
}

Step 3: use them to interact with the web application

// jasmine test using `aft-jasmine-reporter` package
describe('SeleniumSession', () => {
    it('[C1234] can access websites using AFT and UiComponents with AftJasmineTest', async () => {
        await aftJasmineTest(async (v: AftJasmineTest) => {
            const loginMessage: string;
            await using(new SeleniumSession({reporter: v.reporter}), async (session) => {
                const loginPage: HerokuLoginPage = v.getComponent(HerokuLoginPage);
                await v.reporter.step('navigate to LoginPage...');
                await loginPage.navigateTo();
                await v.reporter.step('login');
                await loginPage.login("tomsmith", "SuperSecretPassword!");
                await v.reporter.step('wait for message to appear...')
                await retry(() => loginPage.hasMessage())
                    .withMaxDuration(20000) // 20 seconds
                    .until((res) => res === true);
                await v.reporter.step('get message...');
                loginMessage = await loginPage.getMessage();
            });
            await v.verify(loginMessage, containing("You logged into a secure area!"));
        });
    })

    it('[C2345] can access websites using AFT and UiComponents with AftJasmineReporter', async () => {
        const aft = new AftJasmineTest();
        const shouldRun = await aft.shouldRun();
        if (shouldRun.result !== true) {
            await aft.pending(); // marks test as skipped
        } else {
            await using(new SeleniumSession({reporter: aft.reporter}), async (session) => {
                const loginPage: HerokuLoginPage = v.getComponent(HerokuLoginPage);
                await v.reporter.step('navigate to LoginPage...');
                await loginPage.navigateTo();
                await v.reporter.step('login');
                await loginPage.login("tomsmith", "SuperSecretPassword!");
                await v.reporter.step('wait for message to appear...')
                await retry(() => loginPage.hasMessage())
                    .withMaxDuration(20000) // 20 seconds
                    .until((res) => res === true);
                await v.reporter.step('get message...');
                expect(await loginPage.getMessage()).toContain("You logged into a secure area!");
            });
        }
    })
})

aftconfig.json keys and values supported by aft-ui-selenium package

this package does not support any additional configuration. see aft-ui for values relevant in the UiSessionConfig