automation-extra-plugin
    TypeScript icon, indicating that this package has built-in type declarations

    4.2.1-next.587 • Public • Published

    automation-extra-plugin GitHub Workflow Status Discord npm

    Base class to develop plugins for automation-extra.

    Installation

    yarn add automation-extra-plugin
    Changelog
    • v4.1
      • Initial public release

    Features

    • Supports playwright-extra as well as puppeteer-extra
    • Uses lifecycle events to hook into Puppeteer & Playwright execution
    • Ships with this.env and type guards to make multi-browser, multi-driver plugin development a breeze
    • Written in TypeScript (which means helpful auto-complete even if you're writing your plugins in JS)
    • Successor to puppeteer-extra-plugin, which only supports Puppeteer

    Example

    const { AutomationExtraPlugin } = require('automation-extra-plugin')
    
    class DemoPlugin extends AutomationExtraPlugin {
      constructor(opts = {}) {
        super(opts)
      }
    
      static get id() {
        return 'demo'
      }
    
      async beforeLaunch(options) {
        // Modify launch options
        options.headless = false
      }
    
      async onBrowser(browser) {
        // Become aware of browser launch/connect
        console.log('onBrowser:', {
          driverName: this.env.driverName,
          browserName: this.env.browserName,
        })
      }
    
      async onPageCreated(page) {
        // Hook into page events
        console.log('Page created:', page.url())
        page.on('load', () => {
          console.log('Page loaded', page.url())
        })
        // Use a shim which unifies page.evaluateOnNewDocument and page.addInitScript
        this.shim(page).addScript(() => {
          navigator.alice = 'bob'
        })
      }
    }
    
    const demo = new DemoPlugin()

    Use the plugin with Puppeteer:

    const puppeteer = require('puppeteer-extra')
    
    puppeteer.use(demo) // that's it :-)
    puppeteer.launch({ headless: true }).then(async (browser) => {
      const page = await browser.newPage()
      await page.goto('https://example.com', { waitUntil: 'load' })
      const alice = await page.evaluate(() => navigator.alice)
      console.log(alice) // ==> bob
      await browser.close()
    })

    Use the same plugin with Playwright (chromium and webkit are supported as well):

    const { firefox } = require('playwright-extra')
    
    firefox.use(demo) // that's it :-)
    firefox.launch({ headless: true }).then(async (browser) => {
      // ... same code as above
    })

    Contributing

    If you're interested in releasing your plugin under the @extra organization please reach out to us through an issue or on our discord server. :-)

    API

    Table of Contents

    class: PluginLifecycleMethods

    Plugin lifecycle methods used by AutomationExtraPlugin.

    These are hooking into Playwright/Puppeteer events and are meant to be overriden on a per-need basis in your own plugin extending AutomationExtraPlugin.


    .onPluginRegistered()

    Returns: Promise<void>

    After the plugin has been registered, called early in the life-cycle (once the plugin has been added).


    .beforeLaunch(options)

    • options LaunchOptions Puppeteer/Playwright launch options

    Returns: Promise<(LaunchOptions | void)>

    Before a new browser instance is created/launched.

    Can be used to modify the puppeteer/playwright launch options by modifying or returning them.

    Plugins using this method will be called in sequence to each be able to update the launch options.

    Example:

    async beforeLaunch (options) {
      if (this.opts.flashPluginPath) {
        options.args = options.args || []
        options.args.push(`--ppapi-flash-path=${this.opts.flashPluginPath}`)
      }
    }

    .afterLaunch(browser, launchContext)

    • browser Browser The puppeteer or playwright browser instance.
    • launchContext LaunchContext

    After the browser has launched.

    Note: Don't assume that there will only be a single browser instance during the lifecycle of a plugin. It's possible that pupeeteer.launch will be called multiple times and more than one browser created. In order to make the plugins as stateless as possible don't store a reference to the browser instance in the plugin but rather consider alternatives.

    E.g. when using onPageCreated you can get a browser reference by using page.browser().

    Alternatively you could expose a class method that takes a browser instance as a parameter to work with:

    const fancyPlugin = require('puppeteer-extra-plugin-fancy')()
    puppeteer.use(fancyPlugin)
    const browser = await puppeteer.launch()
    await fancyPlugin.killBrowser(browser)

    Example:

    async afterLaunch (browser, opts) {
      this.debug('browser has been launched', opts.options)
    }

    .beforeConnect(options)

    • options ConnectOptions Puppeteer/playwright connect options

    Returns: Promise<(ConnectOptions | void)>

    Before connecting to an existing browser instance.

    Can be used to modify the puppeteer/playwright connect options by modifying or returning them.

    Plugins using this method will be called in sequence to each be able to update the launch options.


    .afterConnect(browser, launchContext)

    • browser Browser The puppeteer or playwright browser instance.
    • launchContext LaunchContext

    After connecting to an existing browser instance.

    Note: Don't assume that there will only be a single browser instance during the lifecycle of a plugin.


    .onBrowser(browser, launchContext)

    • browser Browser The puppeteer or playwright browser instance.
    • launchContext LaunchContext

    Called when a browser instance is available.

    This applies to both launch and connect.

    Convenience method created for plugins that need access to a browser instance and don't mind if it has been created through launch or connect.

    Note: Don't assume that there will only be a single browser instance during the lifecycle of a plugin.


    .beforeContext(options, browser)

    • options Playwright.BrowserContextOptions Playwright browser context options
    • browser Playwright.Browser Playwright browser

    Returns: Promise<(Playwright.BrowserContextOptions | void)>

    Before a new browser context is created.

    Note: Currently only triggered by playwright, as puppeteer's usage of context is very lackluster.

    Plugins using this method will be called in sequence to each be able to update the context options.


    .onContextCreated(context, options)

    • context Playwright.BrowserContext Playwright browser context
    • options Playwright.BrowserContextOptions Playwright browser context options

    After a new browser context has been created.

    Note: playwright specific.


    .onPageCreated(page)

    • page (Puppeteer.Page | Playwright.Page)

    Called when a page has been created.

    The event will also fire for popup pages.

    Example:

    async onPageCreated (page) {
      let ua = await page.browser().userAgent()
      if (this.opts.stripHeadless) {
        ua = ua.replace('HeadlessChrome/', 'Chrome/')
      }
      this.debug('new ua', ua)
      await page.setUserAgent(ua)
    }

    .onPageClose(page)

    • page Page

    Called when a page has been closed.


    .onContextClose(context)

    • context Playwright.BrowserContext

    Called when a browser context has been closed.

    Note: playwright specific.


    .onDisconnected(browser)

    • browser Browser The puppeteer or playwright browser instance.

    Called when the browser got disconnected.

    This might happen because of one of the following:

    • The browser is closed or crashed
    • The browser.disconnect method was called

    class: AutomationExtraPlugin

    Extends: PluginLifecycleMethods

    AutomationExtraPlugin - Meant to be used as a base class and it's methods overridden.

    Implements all PluginLifecycleMethods.

    Example:

    class Plugin extends AutomationExtraPlugin {
      static id = 'foobar'
      constructor(opts = {}) {
        super(opts)
      }
    
      async beforeLaunch(options) {
        options.headless = false
        return options
      }
    }

    .env

    Type: LauncherEnv

    Contains info regarding the launcher environment the plugin runs in

    • See: LauncherEnv

    .shim(page)

    • page Page

    Returns: PageShim

    Unified Page methods for Playwright & Puppeteer


    .defaults

    Type: PluginOptions

    Plugin defaults (optional).

    If defined will be (deep-)merged with the (optional) user supplied options (supplied during plugin instantiation).

    The result of merging defaults with user supplied options can be accessed through this.opts.

    Example:

    get defaults () {
      return {
        stripHeadless: true,
        makeWindows: true,
        customFn: null
      }
    }
    
    // Users can overwrite plugin defaults during instantiation:
    puppeteer.use(require('puppeteer-extra-plugin-foobar')({ makeWindows: false }))
    • See: [[opts]]

    .requirements

    Type: PluginRequirements

    Plugin requirements (optional).

    Signal certain plugin requirements to the base class and the user.

    Currently supported:

    • launch
      • If the plugin only supports locally created browser instances (no puppeteer.connect()), will output a warning to the user.
    • headful
      • If the plugin doesn't work in headless: true mode, will output a warning to the user.
    • runLast
      • In case the plugin prefers to run after the others. Useful when the plugin needs data from others.

    Example:

    get requirements () {
      return new Set(['runLast', 'dataFromPlugins'])
    }

    .filter

    Type: (Filter | undefined)

    Plugin filter statements (optional).

    Filter this plugin from being called depending on the environment.

    Example:

    get filter() {
      return {
        include: ['playwright:chromium', 'puppeteer:chromium']
      }
    }

    .dependencies

    Type: PluginDependencies

    Plugin dependencies (optional).

    Missing plugins will be required() by automation-extra.

    Example:

    // Will ensure the 'puppeteer-extra-plugin-user-preferences' plugin is loaded.
    get dependencies () {
      return new Set(['user-preferences'])
    }
    
    // Will load `user-preferences` plugin and pass `{ beCool: true }` as opts
    get dependencies () {
      return new Map([['user-preferences', { beCool: true }]])
    }

    .plugins

    Type: Array<AutomationExtraPluginInstance>

    Add additional plugins (optional).

    Expects an array of AutomationExtraPlugin instances, not classes. This is intended to be used by "meta" plugins that use other plugins behind the scenes.

    The benefit over using dependencies is that this doesn't use the framework for dynamic imports, but requires explicit imports which bundlers like webkit handle much better.

    Missing plugins listed here will be added at the start of launch or connect events.


    .opts

    Type: PluginOptions

    Access the plugin options (usually the defaults merged with user defined options)

    To skip the auto-merging of defaults with user supplied opts don't define a defaults property and set the this._opts Object in your plugin constructor directly.

    Example:

    get defaults () { return { foo: "bar" } }
    
    async onPageCreated (page) {
      this.debug(this.opts.foo) // => bar
    }
    • See: [[defaults]]

    .debug

    Type: Debugger

    Convenience debug logger based on the debug module. Will automatically namespace the logging output to the plugin package name.

    # toggle output using environment variables
    DEBUG=automation-extra-plugin:<plugin_id> node foo.js
    # to debug all the things:
    DEBUG=automation-extra,automation-extra-plugin:* node foo.js

    Example:

    this.debug('hello world')
    // will output e.g. 'automation-extra-plugin:anonymize-ua hello world'

    .id

    Plugin id/name (required)

    Convention:

    • Package: automation-extra-plugin-anonymize-ua
    • Name: anonymize-ua

    Example:

    static id = 'anonymize-ua';
    // or
    static get id() {
      return 'anonymize-ua'
    }

    class: TypeGuards

    TypeGuards: They allow differentiating between different objects and types.

    Type guards work by discriminating against properties only found in that specific type. This is especially useful when used with TypeScript as it improves type safety.


    .isPage(obj)

    • obj any The object to test

    Returns: boolean

    Type guard, will make TypeScript understand which type we're working with.


    .isBrowser(obj)

    • obj any The object to test

    Returns: boolean

    Type guard, will make TypeScript understand which type we're working with.


    .isPuppeteerPage(obj)

    • obj any The object to test

    Returns: boolean

    Type guard, will make TypeScript understand which type we're working with.


    .isPuppeteerBrowser(obj)

    • obj any The object to test

    Returns: boolean

    Type guard, will make TypeScript understand which type we're working with.


    .isPuppeteerBrowserContext(obj)

    • obj any The object to test

    Returns: boolean

    Type guard, will make TypeScript understand which type we're working with.


    .isPlaywrightPage(obj)

    • obj any The object to test

    Returns: boolean

    Type guard, will make TypeScript understand which type we're working with.


    .isPlaywrightBrowser(obj)

    • obj any The object to test

    Returns: boolean

    Type guard, will make TypeScript understand which type we're working with.


    .isPlaywrightBrowserContext(obj)

    • obj any The object to test

    Returns: boolean

    Type guard, will make TypeScript understand which type we're working with.


    class: LauncherEnv

    Extends: TypeGuards

    Stores environment specific info, populated by the launcher. This allows sane plugin development in a multi-browser, multi-driver environment.


    .driverName

    The name of the driver currently in use: "playwright" | "puppeteer".


    .browserName

    The name of the browser engine currently in use: "chromium" | "firefox" | "webkit" | "unknown".

    Note: With puppeteer the browser will only be known once a browser object is available (after launching or connecting), as they support defining the browser during .launch().


    .isPuppeteer

    Check if current driver is puppeteer


    .isPlaywright

    Check if current driver is playwright


    .isChromium

    Check if current browser is chrome or chromium


    .isFirefox

    Check if current browser is firefox


    .isWebkit

    Check if current browser is webkit


    .isBrowserKnown

    Check if current browser is known


    class: PageShim

    Unified Page methods for Playwright & Puppeteer. They support common actions through a single API.


    .addScript(script, arg?)

    Adds a script which would be evaluated in one of the following scenarios:

    Whenever the page is navigated. Whenever the child frame is attached or navigated. In this case, the script is evaluated in the context of the newly attached frame.

    The script is evaluated after the document was created but before any of its scripts were run.

    • See: Playwright: addInitScript Puppeteer: evaluateOnNewDocument

    License

    Copyright © 2018 - 2021, berstend̡̲̫̹̠̖͚͓̔̄̓̐̄͛̀͘. Released under the MIT License.

    Install

    npm i automation-extra-plugin

    DownloadsWeekly Downloads

    539

    Version

    4.2.1-next.587

    License

    MIT

    Unpacked Size

    169 kB

    Total Files

    16

    Last publish

    Collaborators

    • berstend