Giter Site home page Giter Site logo

puppeteer / replay Goto Github PK

View Code? Open in Web Editor NEW
923.0 128.0 250.0 1.92 MB

Library that provides an API to replay and stringify recordings created using Chrome DevTools Recorder

License: Apache License 2.0

JavaScript 10.84% TypeScript 82.54% HTML 6.62%
puppeteer javascript automation devtools

replay's Introduction

@puppeteer/replay

Build status npm puppeteer package

Puppeteer Replay is a library that provides an API to replay and stringify recordings created using Chrome DevTools Recorder

Installation

npm install @puppeteer/replay --save

If you want to replay recordings using Puppeteer, install Puppeteer as well:

npm install puppeteer --save

Getting started with Puppeteer Replay

You can use Puppeteer Replay to:

  1. Replay recording. Replay recording with CLI or using the replay lib API.
  2. Customize replay. Customize how a recording is run. For example, capture screenshots after each step or integrate with 3rd party libraries.
  3. Transform recording. Customize how a recording is stringified. For example, transform the recording into another format.

Also, you can use third-party integrations that build on top of @puppeteer/replay, which includes:

Transform JSON user flows to custom scripts:

Replay JSON user flows:

1. Replay recording

Download this example recording and save it as recording.json.

Using CLI + npx:

npx @puppeteer/replay recording.json

Using CLI + package.json:

In your package.json add a new script to invoke the replay command:

{
  "scripts": {
    "replay": "replay recording.json"
  }
}

You can also give folder name as a parameter to run all the files in a folder.

Using CLI + npx:

npx @puppeteer/replay all-recordings # runs all recordings in the "all-recordings" folder.

Using CLI + package.json:

{
  "scripts": {
    "replay": "replay all-recordings"
  }
}

Set the PUPPETEER_HEADLESS environment variable or --headless CLI flag to control whether the browser is started in a headful or headless mode. For example,

PUPPETEER_HEADLESS=true npx @puppeteer/replay recording.json # runs in headless mode, the default mode.
PUPPETEER_HEADLESS=false npx @puppeteer/replay recording.json # runs in headful mode.
PUPPETEER_HEADLESS=chrome npx @puppeteer/replay recording.json # runs in the new experimental headless mode.

Use the --extension CLI flag to provide a custom replay extension for running the recording. For example,

npx @puppeteer/replay --extension examples/cli-extension/extension.js recording.json

Run npx @puppeteer/replay --help to see all CLI options.

Using the replay lib API:

import { createRunner, parse } from '@puppeteer/replay';
import fs from 'fs';

// Read recording for a file.
const recordingText = fs.readFileSync('./recording.json', 'utf8');
// Validate & parse the file.
const recording = parse(JSON.parse(recordingText));
// Create a runner and execute the script.
const runner = await createRunner(recording);
await runner.run();

2. Customize replay

The library offers a way to customize how a recording is run. You can extend the PuppeteerRunnerExtension class as shown in the example below.

Full example of the PuppeteerRunnerExtension: link

import { createRunner, PuppeteerRunnerExtension } from '@puppeteer/replay';
import puppeteer from 'puppeteer';

const browser = await puppeteer.launch({
  headless: true,
});

const page = await browser.newPage();

class Extension extends PuppeteerRunnerExtension {
  async beforeAllSteps(flow) {
    await super.beforeAllSteps(flow);
    console.log('starting');
  }

  async beforeEachStep(step, flow) {
    await super.beforeEachStep(step, flow);
    console.log('before', step);
  }

  async afterEachStep(step, flow) {
    await super.afterEachStep(step, flow);
    console.log('after', step);
  }

  async afterAllSteps(flow) {
    await super.afterAllSteps(flow);
    console.log('done');
  }
}

const runner = await createRunner(
  {
    title: 'Test recording',
    steps: [
      {
        type: 'navigate',
        url: 'https://wikipedia.org',
      },
    ],
  },
  new Extension(browser, page, 7000)
);

await runner.run();

await browser.close();

3. Transform recording

You can customize how a recording is stringified and use it to transform the recording format.

Stringify a recording as a Puppeteer script

import { stringify } from '@puppeteer/replay';

console.log(
  await stringify({
    title: 'Test recording',
    steps: [],
  })
);

Customize how a recording is stringified

You can customize how a recording is stringified by extending the PuppeteerStringifyExtension class as shown in the example below.

Full example of PuppeteerStringifyExtension : link

import { stringify, PuppeteerStringifyExtension } from '@puppeteer/replay';

class Extension extends PuppeteerStringifyExtension {
  // beforeAllSteps?(out: LineWriter, flow: UserFlow): Promise<void>;
  async beforeAllSteps(...args) {
    await super.beforeAllSteps(...args);
    args[0].appendLine('console.log("starting");');
  }

  // beforeEachStep?(out: LineWriter, step: Step, flow: UserFlow): Promise<void>;
  async beforeEachStep(...args) {
    await super.beforeEachStep(...args);
    const [out, step] = args;
    out.appendLine(`console.log("about to execute step ${step.type}")`);
  }

  // afterEachStep?(out: LineWriter, step: Step, flow: UserFlow): Promise<void>;
  async afterEachStep(...args) {
    const [out, step] = args;
    out.appendLine(`console.log("finished step ${step.type}")`);
    await super.afterEachStep(...args);
  }

  // afterAllSteps?(out: LineWriter, flow: UserFlow): Promise<void>;
  async afterAllSteps(...args) {
    args[0].appendLine('console.log("finished");');
    await super.afterAllSteps(...args);
  }
}

console.log(
  await stringify(
    {
      title: 'Test recording',
      steps: [
        {
          type: 'navigate',
          url: 'https://wikipedia.org',
        },
      ],
    },
    {
      extension: new Extension(),
      indentation: '	', // use tab to indent lines
    }
  )
);

Others

Test your extensions using the replay lib

The replay lib offers a canonical recording and a test page that allows to verify that your extension produces all expected side effects on a page.

The test command supports both stringify and runner extensions. The stringify extension will be tested by running the stringified script using node. Run the test using the following command.

npx -p @puppeteer/replay replay-extension-test --ext path-to-your-extension-js

Create a Chrome extension for Recorder (Available from Chrome 104 onwards)

You can create a Chrome extension for Recorder. Refer to the Chrome Extensions documentation for more details on how to extend DevTools.

For example, here are some of the third party extensions:

This feature only available from Chrome 104 onwards. Check your current Chrome version with chrome://version. Consider installing Chrome Canary to try out cutting-edge features in Chrome.

This repository contains an example extension. Once installed, the Recorder will have a new export option Export as a Custom JSON script in the export dropdown.

To load the example into Chrome DevTools. Follow these steps:

  1. Download the chrome-extension folder.
  2. Load the folder as unpacked extension in Chrome.
  3. Open a recording in the Recorder.
  4. Click on export. Now you can see a new Export as a Custom JSON script option in the export menu.

Click and watch the video demo below:

Demo video that shows how to extend export options in Recorder panel by adding a Chrome extension

replay's People

Contributors

abhishek-mallick avatar adamraine avatar almog-geva avatar das7pad avatar dependabot[bot] avatar ergunsh avatar jecfish avatar jrandolf avatar lightning00blade avatar mathiasbynens avatar nickmccurdy avatar orkon avatar paulirish avatar puskuruk avatar release-please[bot] avatar s4l4x avatar sofiayem avatar thovden avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

replay's Issues

Huawei

Expected Behavior

Actual Behavior

Steps to Reproduce the Problem

Specifications

  • Version:
  • Platform:

Add an example complete JSON file for extension builder to test

Should we add that under the examples repo?

I have updated the coffee demo to include our latest supported actions. The below JSON is consider quite complete:

  • Set viewport
  • navigate
  • click
  • hover
  • double click
  • right click
  • keydown
  • keyup
  • waitForExpression
  • waitForElement (with operator and count)
{
  "title": "order-a-coffee-complete",
  "steps": [
    {
      "type": "setViewport",
      "width": 448,
      "height": 768,
      "deviceScaleFactor": 1,
      "isMobile": false,
      "hasTouch": false,
      "isLandscape": false
    },
    {
      "type": "navigate",
      "url": "https://coffee-cart.netlify.app/",
      "assertedEvents": [
        {
          "type": "navigation",
          "url": "https://coffee-cart.netlify.app/",
          "title": "Coffee cart"
        }
      ]
    },
    {
      "type": "click",
      "target": "main",
      "selectors": [
        [
          "aria/Espresso"
        ],
        [
          "[data-test=Espresso]"
        ]
      ],
      "offsetY": 128.0280532836914,
      "offsetX": 157.40187072753906
    },
    {
      "type": "click",
      "target": "main",
      "selectors": [
        [
          "aria/Americano"
        ],
        [
          "[data-test=Americano]"
        ]
      ],
      "offsetY": 110.07492065429688,
      "offsetX": 146.40187072753906
    },
    {
      "type": "click",
      "target": "main",
      "selectors": [
        [
          "aria/Mocha"
        ],
        [
          "[data-test=Mocha]"
        ]
      ],
      "offsetY": 117.84835815429688,
      "offsetX": 138.40187072753906,
      "button": "secondary"
    },
    {
      "type": "click",
      "target": "main",
      "selectors": [
        [
          "aria/Yes"
        ],
        [
          "[data-cy=add-to-cart-modal] > form > button:nth-child(1)"
        ]
      ],
      "offsetY": 19,
      "offsetX": 28.4765625
    },
    {
      "type": "doubleClick",
      "target": "main",
      "selectors": [
        [
          "aria/Flat White $18.00"
        ],
        [
          "#app > div:nth-child(4) > ul > li:nth-child(5) > h4"
        ]
      ],
      "offsetY": 5.734375,
      "offsetX": 46
    },
    {
      "type": "doubleClick",
      "target": "main",
      "selectors": [
        [
          "aria/平白咖啡 $18.00"
        ],
        [
          "#app > div:nth-child(4) > ul > li:nth-child(5) > h4"
        ]
      ],
      "offsetX": 45,
      "offsetY": 5.734375
    },
    {
      "type": "click",
      "target": "main",
      "frame": [],
      "selectors": [
        [
          "aria/Flat White"
        ],
        [
          "[data-test=Flat_White]"
        ]
      ],
      "offsetX": 0,
      "offsetY": 0,
      "button": "secondary"
    },
    {
      "type": "keyDown",
      "key": "Escape"
    },
    {
      "type": "hover",
      "selectors": [
        [
          "aria/Proceed to checkout"
        ],
        [
          "[data-test=checkout]"
        ]
      ],
      "frame": [],
      "target": "main"
    },
    {
      "type": "click",
      "target": "main",
      "selectors": [
        [
          "aria/Add one Espresso"
        ],
        [
          "#app > div:nth-child(4) > div.pay-container > ul > li:nth-child(2) > div.unit-controller > button:nth-child(1)"
        ]
      ],
      "offsetY": 13.1875,
      "offsetX": 8.15625
    },
    {
      "type": "click",
      "target": "main",
      "selectors": [
        [
          "aria/Remove one Mocha"
        ],
        [
          "#app > div:nth-child(4) > div.pay-container > ul > li:nth-child(3) > div.unit-controller > button:nth-child(2)"
        ]
      ],
      "offsetY": 10.4921875,
      "offsetX": 8
    },
    {
      "type": "waitForElement",
      "target": "main",
      "frame": [],
      "selectors": [
        [
          "div.pay-container li"
        ]
      ],
      "operator": "==",
      "count": 2
    },
    {
      "type": "waitForExpression",
      "expression": "document.querySelector('div.pay-container li:nth-child(2) span.unit-desc').innerText === ' x 2'"
    },
    {
      "type": "click",
      "target": "main",
      "selectors": [
        [
          "aria/Proceed to checkout"
        ],
        [
          "[data-test=checkout]"
        ]
      ],
      "offsetY": 19.796875,
      "offsetX": 136.1875
    },
    {
      "type": "click",
      "target": "main",
      "selectors": [
        [
          "aria/Name"
        ],
        [
          "#name"
        ]
      ],
      "offsetY": 13.90625,
      "offsetX": 72.21875
    },
    {
      "type": "change",
      "value": "jec",
      "selectors": [
        [
          "aria/Name"
        ],
        [
          "#name"
        ]
      ],
      "target": "main"
    },
    {
      "type": "keyDown",
      "target": "main",
      "key": "Tab"
    },
    {
      "type": "keyUp",
      "key": "Tab",
      "target": "main"
    },
    {
      "type": "change",
      "value": "[email protected]",
      "selectors": [
        [
          "aria/Email"
        ],
        [
          "#email"
        ]
      ],
      "target": "main"
    },
    {
      "type": "click",
      "target": "main",
      "selectors": [
        [
          "aria/Promotion message"
        ],
        [
          "#promotion-label"
        ]
      ],
      "offsetY": 16.515625,
      "offsetX": 120.203125
    },
    {
      "type": "click",
      "target": "main",
      "selectors": [
        [
          "aria/Submit"
        ],
        [
          "#submit-payment"
        ]
      ],
      "offsetY": 26.125,
      "offsetX": 53.15625
    }
  ]
}

Provide a better status report for multiple recordings

Recorder panel and @puppeteer/replay library makes it a lot easier to start writing E2E tests. For a small project of mine, I was able to have a basic E2E setup using Recorder panel in around 5 minutes :)

Though currently running multiple files doesn't provide a good status report at the end: i.e. these replays succeeded and this failed with reason X.

So, if we provide a better status report; users will be able to use this as a basic recorder runner maybe to have their initial tests in their codebase.

Jest Integration

I ideally would like to add this project and use it for my e2e unit tests, using jest. I've come into the issue of getting Jest to play nicely with the cjs version of the project. However, I am curious if we could add documentation or better accommodate Jest support?

Can you add a step to type a string text in a contenteditible element?

Currently with the replay scriptRunner, we can only enter an element with a "keyDown" which only does one key at a time, however these days many apps and plugins like prose mirror use contenteditable which means we can't use the "change" step which assumes an input.

Would you consider adding the "page.type" as a step type? Without something like this to type into contenteditable elements, the framework's usefulness becomes limited but with this it will be incredibly useful.
https://pptr.dev/api/puppeteer.page.type/

Alternatively, enabling the ability to add our own custom steps would be great. I saw something in the docs about a custom step but it looks like it hasn't been implemented.

Typescript CommonJS replay clients are broken when using moduleResolution nodenext

Expected Behavior

Typescript clients using "moduleResolution": "nodenext" with "module": "commonjs" should be able to import the package. I have a large monorepo with a mix of CommonJS and ESM modules, and want to use Node 16+ module resolution across the monorepo.

Actual Behavior

Typescript is unable to import the file, with error:

The current file is a CommonJS module whose imports will produce 'require' calls; however, the referenced file is an ECMAScript module and cannot be imported with 'require'. Consider writing a dynamic 'import("@puppeteer/replay")' call instead.
  To convert this file to an ECMAScript module, change its file extension to '.mts', or add the field `"type": "module"` to 'puppeteer-client/package.json'.ts

The issue is discussed here: microsoft/TypeScript#50466

Steps to Reproduce the Problem

  1. Clone https://github.com/signatu/puppeteer-replay-import-error
  2. npm i
  3. npm run build

The repository is very simple, and the main trigger is the tsconfig.json below:

{
        "module": "commonjs",
        "moduleResolution": "nodenext"
}

Fix

The fix is to provide a separate type file cjs/main.d.cts for the .cjs CommonJS module, and refer to that in package.json:

  "exports": {
    ".": {
      "import": {      
        "types": "./lib/main.d.ts",
        "default": "./lib/main.js"
      }, 
      "require": {
        "types": "./lib/cjs/main.d.cts",
        "default": "./lib/cjs/main.cjs"
      }
    }
  },

I'll submit a PR for this change.

Specifications

  • Version: 2.6.0
  • Platform: MacOS 13.0.1

Add `BASE_URL` support

When you have multiple environments you might want to run your tests with different base URLs for each environment. For example:

BASE_URL=http://www.staging.your-awesome-application.com npx @puppeteer/replay recording.json
BASE_URL=http://www.test.your-awesome-application.com npx @puppeteer/replay recording.json

Gh

adb devices

Originzer

Now
2022-11-06T11:29:15.005-05:00

Next alarm clock (on device)
2022-11-07T07:00:00.000-05:00

Last run for reminders
Scheduled
2022-11-06T11:29:12.429-05:00
Deadline
2022-11-06T11:29:12.429-05:00
Event
2022-11-06T11:29:12.429-05:00

Last boot (including deep sleep)
2022-11-06T10:34:58.720-05:00
54 minutes, 16 seconds and 285 milliseconds
2022-11-06T11:29:10.718-05:00 reminders Intent accepted - scheduled time reminder is enabled: Intent { act=com.orgzly.intent.action.REMINDER_DATA_CHANGED flg=0x10 cmp=com.orgzly/.android.reminders.RemindersBroadcastReceiver }
2022-11-06T11:29:10.742-05:00 reminders Canceled all reminders
2022-11-06T11:29:10.793-05:00 reminders Since last run: No notes found between LastRun(scheduled=2022-11-06T11:29:03.330-05:00, deadline=2022-11-06T11:29:03.330-05:00, event=2022-11-06T11:29:03.330-05:00) and 2022-11-06T11:29:10.737-05:00
2022-11-06T11:29:10.819-05:00 reminders Next: No notes found from 2022-11-06T11:29:10.737-05:00
2022-11-06T11:29:12.425-05:00 reminders Intent accepted - scheduled time reminder is enabled: Intent { act=com.orgzly.intent.action.REMINDER_DATA_CHANGED flg=0x10 cmp=com.orgzly/.android.reminders.RemindersBroadcastReceiver }
2022-11-06T11:29:12.433-05:00 reminders Canceled all reminders
2022-11-06T11:29:12.463-05:00 reminders Since last run: No notes found between LastRun(scheduled=2022-11-06T11:29:10.737-05:00, deadline=2022-11-06T11:29:10.737-05:00, event=2022-11-06T11:29:10.737-05:00) and 2022-11-06T11:29:12.429-05:00
2022-11-06T11:29:12.480-05:00 reminders Next: No notes found from 2022-11-06T11:29:12.429-05:00

  • now
    2022-11-06t11:29:15.005-05:00

next alarm clock (on device)
2022-11-07t07:00:00.000-05:00

last run for reminders
scheduled
2022-11-06t11:29:12.429-05:00
deadline
2022-11-06t11:29:12.429-05:00
event
2022-11-06t11:29:12.429-05:00

last boot (including deep sleep)
2022-11-06t10:34:58.720-05:00
54 minutes, 16 seconds and 285 milliseconds
2022-11-06t11:29:10.718-05:00 reminders intent accepted - scheduled time reminder is enabled: intent { act=com.orgzly.intent.action.reminder_data_changed flg=0x10 cmp=com.orgzly/.android.reminders.remindersbroadcastreceiver }
2022-11-06t11:29:10.742-05:00 reminders canceled all reminders
2022-11-06t11:29:10.793-05:00 reminders since last run: no notes found between lastrun(scheduled=2022-11-06t11:29:03.330-05:00, deadline=2022-11-06t11:29:03.330-05:00, event=2022-11-06t11:29:03.330-05:00) and 2022-11-06t11:29:10.737-05:00
2022-11-06t11:29:10.819-05:00 reminders next: no notes found from 2022-11-06t11:29:10.737-05:00
2022-11-06t11:29:12.425-05:00 reminders intent accepted - scheduled time reminder is enabled: intent { act=com.orgzly.intent.action.reminder_data_changed flg=0x10 cmp=com.orgzly/.android.reminders.remindersbroadcastreceiver }
2022-11-06t11:29:12.433-05:00 reminders canceled all reminders
2022-11-06t11:29:12.463-05:00 reminders since last run: no notes found between lastrun(scheduled=2022-11-06t11:29:10.737-05:00, deadline=2022-11-06t11:29:10.737-05:00, event=2022-11-06t11:29:10.737-05:00) and 2022-11-06t11:29:12.429-05:00
2022-11-06t11:29:12.480-05:00 reminders next: no notes found from 2022-11-06t11:29:12.429-05:00

Hg

adb devices

Large bundle size with webpack

Actual Behavior

I'm making a Chrome recorder extension, and I've noticed the production library bundle was 437KB in my project, which I would consider to be relatively large for a bundle that doesn't need to ship GUI assets. I'm guessing this is due to a combination of Node.js dependencies and Puppeteer not being originally designed for browser usage (since the DOM and Selenium APIs already support browser automation). This issue may also apply to Puppeteer's build, but I wanted to open it here because it's related to the recorder use case.

Steps to Reproduce the Problem

  1. Clone https://gist.github.com/ad7d2641f9b7b8c6012d031edab790c4
  2. npm install
  3. Note the sizes outputted by webpack or on disk

Specifications

  • Version: 0.6.1
  • Platform: macOS

How to slow it down?

Expected Behavior

A user can configure a delay between steps when running a flow.

Actual Behavior

Replay script has no apparent option to configure the delay between steps. Sometimes the transition between pages or steps is too fast and breaks expectations causing flakiness in tests.

Steps to Reproduce the Problem

  1. Record a flow in Chrome Dev Tools
  2. Download the flow as Replay script
  3. Run the script

Specifications

  • Version:
  • Platform:

Run all recording files in a directory with CLI

Expected Behavior

When you have a folder structure like below:

- index.js
- package-lock.json
- package.json
- recordings
  - testFile-1.json
  - testFile-2.json

You should be able to run all of the recoding files in the recordings folder with npx @puppeteer/replay ./recordings.

Actual Behavior

Right now, we can only run file paths from CLI.

CLI is broken with the (recent?) changes

npm i @puppeteer/replay -g
❯ replay examples/replay-from-file-using-puppeteer/recording.json
Running examples/replay-from-file-using-puppeteer/recording.json...
(node:16587) Warning: To load an ES module, set "type": "module" in the package.json or use the .mjs extension.
(Use node --trace-warnings ... to show where the warning was created)
Error running examples/replay-from-file-using-puppeteer/recording.json /Users/alexrudenko/src/puppeteer/lib/esm/puppeteer/puppeteer.js:16
import { initializePuppeteer } from './initializePuppeteer.js';
^^^^^^

SyntaxError: Cannot use import statement outside a module
at Object.compileFunction (node:vm:352:18)
at wrapSafe (node:internal/modules/cjs/loader:1031:15)
at Module._compile (node:internal/modules/cjs/loader:1065:27)
at Object.Module._extensions..js (node:internal/modules/cjs/loader:1153:10)
at Module.load (node:internal/modules/cjs/loader:981:32)
at Function.Module._load (node:internal/modules/cjs/loader:822:12)
at ModuleWrap. (node:internal/modules/esm/translators:190:29)
at ModuleJob.run (node:internal/modules/esm/module_job:185:25)
at async Promise.all (index 0)
at async ESMLoader.import (node:internal/modules/esm/loader:281:24)

Incorrect example in docs

docs/api/interfaces/Schema.WaitForExpressionStep.md

Expected Behavior

{
  "type": "waitForExpression",
  "expression": "new Promise(resolve => setTimeout(() => resolve(true),
2000))",
}

Actual Behavior

{
  "type": "waitForElement",
  "expression": "new Promise(resolve => setTimeout(() => resolve(true),
2000))",
}

Steps to Reproduce the Problem

n/a

Specifications

n/a

Ship CJS modules?

Currently, the replay lib only ships ESM modules and has type=module specified in the package.json. Should we also ship CJS alongside ESMs?

CLI never completes execution when there is an error in replay

Expected Behavior

CLI should report the error and complete the execution

Actual Behavior

Execution hangs and you need to press Ctrl + C to cancel execution

Steps to Reproduce the Problem

  1. Save the attached replay
  2. Run npx @puppeteer/replay <saved-recording-path>

You can make the json pass by removing --wrong from the selector in the click step.

Specifications

  • Version: @puppeteer/replay 0.1.2
  • Platform: MacOS

Attachment

{
  "title": "hn-app-refresh",
  "steps": [
    {
      "type": "setViewport",
      "width": 1280,
      "height": 1361,
      "deviceScaleFactor": 1,
      "isMobile": false,
      "hasTouch": false,
      "isLandscape": false
    },
    {
      "type": "navigate",
      "url": "https://hn-vanilla-pwa.ergunsh.vercel.app/",
      "assertedEvents": [
        {
          "type": "navigation",
          "url": "https://hn-vanilla-pwa.ergunsh.vercel.app/",
          "title": "HN App"
        }
      ]
    },
    {
      "type": "click",
      "selectors": [
        [
          "#postListContainer--wrong > div > div:nth-child(1) > h4"
        ]
      ],
      "target": "main",
      "offsetX": 148,
      "offsetY": 10.5625
    }
  ]
}

PuppeteerRunnerExtension requirnig browser and page is cumbersome

This module can simply be used by calling one method (createRunner), however, to customize the behavior, one needs to create an PuppeteerRunnerExtension, and this one requires passing browser and page.

for simplicity, it would be better if an Extension would not requiring these, but would inherit the ones that I assume are created by createRunner

Expected Behavior

const runner = await createRunner(recording, new Extension() );

Actual Behavior

const browser = await puppeteer.launch({
  headless: true,
});

const page = await browser.newPage();

const runner = await createRunner(recording, new Extension(browser, page, 7000) );

Step Delay Property

Add Step Delay Property

I think it would be useful for allowing the user to set a step delay between each step. This can help seeing step by step what could cause the issue.

Clear

aliasELHU EMKPI
ELVIS MUNYI KIIRU
QUEER $-D-C libri cotrecravo qui scannerizza acquisito
ESERCXA.I.I.CACTSATSATACT
[email protected]
PANSCADA.IDAPPLTTTatcccc
unTRcCabBdTVRCFBFAEC
IADa N.VEYXWB
Il bando 03/4 -A<0,5
CBDTHC.IT
LOTTO 242/2016.L:www.dottorcanapa.it
ELVIS MUNYI KIIRU
ALIAS elhu emkpi

What is this?

Who are you im a kelly-ann phylis cassidy from albion, site builder domains v r™®© located on Drummartin and Ive been dealing with depression loss of family loss of children and i cannot

Missing dependency: lighthouse

Expected Behavior

The @puppeteer/replay is compiled without errors when it is installed as a dependency.

Actual Behavior

An error occurs when I bundle my app:

[vite]: Rollup failed to resolve import "lighthouse/core/fraggle-rock/api.js" from "node_modules/@puppeteer/replay/lib/main.js".

This is due to lighthouse missing from the dependencies and/or peerDependencies in package.json. lighthouse is listed only as a devDependency, while in fact it is a normal dependency since the library source depends on it.

Steps to Reproduce the Problem

  1. npm create vite@latest my-app -- --template vanilla
  2. cd my-app && npm install
  3. npm install --save @puppeteer/replay
  4. Import from @puppeteer/replay in the main.js file:
    import { PuppeteerRunnerExtension } from '@puppeteer/replay'
  5. npm run build

Specifications

Types issue: TS2307: Cannot find module 'lighthouse/types/lhr/flow' or its corresponding type declarations

Expected Behavior

tsc works fine

Actual Behavior

node_modules/@puppeteer/replay/lib/main.d.ts:2:24 - error TS2307: Cannot find module 'lighthouse/types/lhr/flow' or its corresponding type declarations.

Steps to Reproduce the Problem

  1. Install @puppeteer/replay
  2. Reference it in a TypeScript file
  3. Compile TypeScript

Specifications

  • Version: 1.2.0, 1.2.1. Caused by #281 (e3ace90)
  • Platform: Node 18.8.0, npm 8.18.1, Windows 10

Improve error handling

For example, should the hooks like afterEach/afterAll be invoked when an error happens? I think it'd be expected if they are still invoked on errors.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.