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

page-framework

v0.3.2

Published

Page object / page modules implementation, for puppeteer. 100% TypeScript.

Downloads

4

Readme

page-framework

Page object / page modules implementation, for puppeteer. 100% TypeScript.

Description

Library powered by puppeteer helps in write well-structured browser automation.

  • Automates Chrome / Chromium browser in very performant way (thanks for puppeteer team)
  • Implements Page object / Page modules pattern
  • Simplifies and extends puppeteer API to handle WebElements
  • Simplifies WebElement locators and let's mix different kinds of them.
  • Uses newest JavaScript ES6+ / TypeScript features.

What You can do with this lib

  • Define complex locators in simple way: $(".img").$x("../../div") (mixed CSS and XPATH)
  • separate locators and their bahavior in page modules, and page objects
  • Run tests in parallel using different runners (jest is recommended as default runner)
  • Evaluate JavaScript directly in Browser console

Getting started

1. Install package

npm i puppeteer page-framework
#OR yarn add puppeteer-page-framework

2. Using package:

Only one requirement from library is page(from puppeteer) in global scope. We recommend jest test frameworkto run tests, there is ready solution (jest-puppeteer): https://jestjs.io/docs/en/puppeteer.

Use without jest framework HERE to it so:

#Functionalities description

Simple use element matchers

const button = $(".myButton")
const form = $("//div[@class='container']").$(".my-form");
const loginField = form.$(".login")
const passwordField = form.$(".pass")

await button.click();
await loginField.type("mylogin[Enter]")
await passwordField.type("mypass123")

Matchers description

At the core of framework are Element Matcher.

  • It represent's way to localize it with different kinds of selectors (CSS, XPATH).
  • Provide's extendable API to handle element properties and actions (such as click(), getText(), eval() and more).
  • It became as Proxy - selector is evaluated while it's really needed - just before click, read, eval is performed)
const simpleCssMatcher = $(".some.css > selector");

After evaluate above expression any request to the browser isn't sent. Request will be send after make an action on the page. For example:

const simpleCssMatcher = $(".some.css > selector");
await simpleCssMatcher.click(); // here, action is evaluated

The same in shorter way:

await $(".some.css > selector").click();

Matcher's can have children:

const elem = $(".some.css").$(".child.selector").$(".child.of.child")

await elem.click();

Matcher's can match elements by XPATH selector.

Note the name of method: $x() for XPATH instead $() for CSS.

$x("//some/xpath/selector/..")

...or combine both ways

$x("//some/xpath/selector/..").$("nested.css.selector");

By default matches first found element, but behavior can be changed with second parameter:

$x("//some/xpath/selector/..", 3)  // - matches third found element
$(".some.css", 3)  // - works for css too

There is possibility to match collections:

const elems = $$("ul > li")  // - matches every element from list
const xpathElems = $$x("//ul/li")  // - works for xpath too

// Results can be mapped - grab text from every element
const textArray = await elems.map(el => el.getText());

// Can be iteratd - click every element
await xpathElems.forEach(el => el.click());

// And filtered
const filtered = await xpathElems.filter(el => {
    (await el.getText()).includes("search text");
});

// Or just get found element handles
const handles = await elems.findAll(); // Returns Array
const firstElem = handles[0];
// ...
// some code
// ...
await firstElem.click()

Of course sub-elements still works as arrays:

elems = $(".some.parent").$x("//ul").$$("li");
await elems.forEach(e => console.log(e.getText())) 

#Use without JEST framework Alternative way

//SOMEWHERE AT THE BEGINNING OF THE SCRIPT
const BrowserUtils = require("page-framework").BrowserUtils;

(async () => {
    await BrowserUtils.initBrowser({ headless: false });
})()

Good place to put it is beforeAll() hook in Your test framework (this is working example for JEST)

describe("My test", () => {
    beforeAll(async () => {
        await BrowserUtils.init({ headless: false });
    })

    afterAll(async () => {
        await BrowserUtils.disconnect(); // don't forget to close the browser.
    })

    it("my test", async () => {
        await page.open("http://www.example.com")
        await $("h1").click();
    })
})

Working example in pure JS ES6+:

const framework = require("page-framework")
const BrowserUtils = framework.BrowserUtils;
const $ = framework.$;

(async () => {
    await BrowserUtils.init({ headless: false });
    await page.goto("http://www.example.com");
    const txt = await $("h1").getText();

    console.log(txt);
    page.close(); // comment this line to keep the browser alive
})()

Working example in pure TypeScript:

import { Page as PuppeteerPage } from "puppeteer";
import { $, BrowserUtils } from "page-framework";

declare var page: PuppeteerPage;

(async () => {
    await BrowserUtils.init({ headless: false });
    await page.goto("http://www.example.com");
    const txt = await $("h1").getText();

    console.log(txt);
    page.close(); // comment this line to keep the browser alive
})()

Development

Tasks to do:

  • [x] Browser launcher class
  • [x] Element proxy mechanism
  • [x] Slector abstraction
  • [x] Fluent interface for selectors
  • [x] Refactor -> create separated Matcher class
  • [x] Add documentation with examples in JavaScript / TypeScript
  • [x] use puppeteer-keyboard
  • [x] $(".elem").module(ModuleName)
  • [x] Add unit tests
  • [ ] Create examples folder with basic use cases
  • [ ] Implement iterator: $$(".col")[2] -> should return matcher: $(".col", 3)
  • [x] Implement MatcherArray -> count()
  • [ ] REFACTOR:
    • [ ] Extract Browser client behind interface
    • [ ] encapsulate selectors hierarchy in one master-class (without "parent" fields)