I'm trying to test this Chrome extension using Puppeteer. My tests run fine locally, but it would not work in GitHub Actions. I suspect the problem to be GitHub Actions environment which Puppeteer is run, but I am not so sure what the root problem is.
I tried all linux-latest, windows-latest, and macos-latest for config.yml's runs-on option, and they gave me different error messages:
linux-latest
Failed to launch the browser process!
[2801:2801:0606/033446.894051:ERROR:browser_main_loop.cc(1468)] Unable to open X display.
Received signal 11 SEGV_MAPERR 000000000000
#0 0x5617d755b399 base::debug::CollectStackTrace()
#1 0x5617d74bc2a3 base::debug::StackTrace::StackTrace()
#2 0x5617d755af35 base::debug::(anonymous namespace)::StackDumpSignalHandler()
#3 0x7efd5b4f6890 (/lib/x86_64-linux-gnu/libpthread-2.27.so+0x1288f)
#4 0x5617d9f51f38 ChromeBrowserMainExtraPartsViewsLinux::~ChromeBrowserMainExtraPartsViewsLinux()
#5 0x5617d7103140 ChromeBrowserMainParts::~ChromeBrowserMainParts()
#6 0x5617d7102cfe ChromeBrowserMainPartsLinux::~ChromeBrowserMainPartsLinux()
#7 0x5617d57fc1bf content::BrowserMainLoop::~BrowserMainLoop()
#8 0x5617d57fc2ce content::BrowserMainLoop::~BrowserMainLoop()
#9 0x5617d5800c2b content::BrowserMainRunnerImpl::Shutdown()
#10 0x5617d5800738 content::BrowserMainRunnerImpl::~BrowserMainRunnerImpl()
#11 0x5617d57fbd30 content::BrowserMain()
#12 0x5617d7086796 content::ContentMainRunnerImpl::RunServiceManager()
#13 0x5617d70863c7 content::ContentMainRunnerImpl::Run()
#14 0x5617d70e7ad1 service_manager::Main()
#15 0x5617d7084631 content::ContentMain()
#16 0x5617d4ada5ae ChromeMain
#17 0x7efd54e61b97 __libc_start_main
#18 0x5617d4ada3ea _start
r8: 0000000000000000 r9: 0000000000000001 r10: 0000000000000002 r11: 00001471e8e09708
r12: aaaaaaaaaaaaaaaa r13: 00001471e8df6a50 r14: 00001471e8e09878 r15: 00001471e8d52460
di: 00001471e8e09840 si: 00001471e8ea4220 bp: 00007ffedc9b6d30 bx: 00001471e8e09840
dx: 00001471e8ea4220 ax: 0000000000000000 cx: fffffffd4f415a7b sp: 00007ffedc9b6d20
ip: 00005617d9f51f38 efl: 0000000000010202 cgf: 002b000000000033 erf: 0000000000000004
trp: 000000000000000e msk: 0000000000000000 cr2: 0000000000000000
[end of stack trace]
Calling _exit(1). Core file will not be generated.
[0606/033446.978197:ERROR:nacl_helper_linux.cc(308)] NaCl helper process running without a sandbox!
Most likely you need to configure your SUID sandbox correctly
TROUBLESHOOTING: https://github.com/puppeteer/puppeteer/blob/master/docs/troubleshooting.md
at onClose (node_modules/puppeteer/lib/launcher/BrowserRunner.js:159:20)
at Interface.helper_1.helper.addEventListener (node_modules/puppeteer/lib/launcher/BrowserRunner.js:149:65)
This happens during puppeteer.launch(). I tried --no-sandbox and --disable-setuid-sandbox flags but didn't do anything.
windows-latest
net::ERR_BLOCKED_BY_CLIENT at chrome-extension://acdcddifhaiiiagbodmcnebcgdmlgdkl/popup/popup.html
> 20 | await page.goto('chrome-extension://acdcddifhaiiiagbodmcnebcgdmlgdkl/popup/popup.html');
at navigate (node_modules/puppeteer/lib/FrameManager.js:95:23)
-- ASYNC --
at Frame.<anonymous> (node_modules/puppeteer/lib/helper.js:94:19)
at Page.goto (node_modules/puppeteer/lib/Page.js:476:53)
at Page.goto (node_modules/puppeteer/lib/helper.js:95:27)
at Object.beforeEach (tests/e2e.test.js:20:16)
This happens when I go to my extension's html page using page.goto().
macos-latest
Timeout - Async callback was not invoked within the 30000 ms timeout specified by jest.setTimeout.Error: Timeout - Async callback was not invoked within the 30000 ms timeout specified by jest.setTimeout.
at mapper (node_modules/jest-jasmine2/build/queueRunner.js:29:45)
TimeoutError: Timed out after 30000 ms while trying to connect to the browser! Only Chrome at revision r756035 is guaranteed to work.
at onTimeout (node_modules/puppeteer/lib/launcher/BrowserRunner.js:170:20)
at Timeout.task (node_modules/jsdom/lib/jsdom/browser/Window.js:391:19)
These two timeout error happens in different places.
This is my beforeEach() which fails to successfully execute on GitHub Actions:
beforeEach (async () => {
browser = await puppeteer.launch({
headless: false,
args: [
`--disable-extensions-except=${extensionPath}`,
`--load-extension=${extensionPath}`
],
slowMo: 50
});
page = await browser.newPage();
await page.goto('chrome-extension://acdcddifhaiiiagbodmcnebcgdmlgdkl/popup/popup.html');
});
This is jobs section of my config.yml:
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout#v2
- name: Use Node.js
uses: actions/setup-node#v1
- name: Install dependencies
run: npm ci
- name: Run Extension
run: npm run build
- name: Run tests
run: npm run test
I'm using the latest version of Puppeteer (v3.1.0) and using Jest (v26.0.1) to run my test file. My other tests (unit tests just with Jest) runs with no issue. The extension uses Vue.js but I don't think it matters.
Edit
Running with headless: true on local machine gives an error as well. It's Windows 10 it it matters:
net::ERR_ABORTED at chrome-extension://acdcddifhaiiiagbodmcnebcgdmlgdkl/popup/popup.html
> 23 | await page.goto('chrome-extension://acdcddifhaiiiagbodmcnebcgdmlgdkl/popup/popup.html');
at navigate (node_modules/puppeteer/lib/FrameManager.js:120:37)
at FrameManager.navigateFrame (node_modules/puppeteer/lib/FrameManager.js:94:17)
at Frame.goto (node_modules/puppeteer/lib/FrameManager.js:406:12)
at Page.goto (node_modules/puppeteer/lib/Page.js:672:12)
at Object.<anonymous> (tests/e2e.test.js:23:5)
-- ASYNC --
at Frame.<anonymous> (node_modules/puppeteer/lib/helper.js:111:15)
at Page.goto (node_modules/puppeteer/lib/Page.js:672:49)
at Page.goto (node_modules/puppeteer/lib/helper.js:112:23)
at Object.<anonymous> (tests/e2e.test.js:23:16)
I would suggest the following changes:
In the code
beforeEach (async () => {
browser = await puppeteer.launch({
headless: true,
args: [
`--no-sandbox`
`--disable-setuid-sandbox`
`--disable-extensions-except=${extensionPath}`,
`--load-extension=${extensionPath}`
],
slowMo: 50
});
page = await browser.newPage();
await page.goto('chrome-extension://acdcddifhaiiiagbodmcnebcgdmlgdkl/popup/popup.html');
});
As Sirko advised: always use headless: true if you are running puppeteer in GitHub Actions, "headful" Chromium causes problems running in a workflow.
--no-sandbox and --disable-setuid-sandbox may be also required, do not remove them even if they haven't solved your issue previously!
In config.yml:
If you want to use puppeteer 3+ you will need to install libgbm1 to run it headless on unix (see puppeteer docs).
[...]
runs-on: ubuntu-latest
[...]
steps:
- name: install puppeteer libraries
run: |
sudo apt-get update
sudo apt-get install -y libgbm1
[...]
If you don't need all latest puppeteer 3 features: you can downgrade to 2.1.1, which doesn't require additional libraries.
Edit: After the new info about headless: true fails locally
According to puppeteer 3.1.0's api.MD the issue is most probably:
Extensions in Chrome / Chromium currently only work in non-headless mode.
while by default you are unable to run puppeteer in Github Actions headful, only headless.
Solution:
What could help you out is a GitHub Action called: puppeteer-headful.
After you've followed the instructions on the Actions page how to configure your config.yml you will need to make sure to launch puppeteer like this:
beforeEach (async () => {
browser = await puppeteer.launch({
executablePath: process.env.PUPPETEER_EXEC_PATH, // set by docker container
headless: false,
args: [
`--disable-extensions-except=${extensionPath}`,
`--load-extension=${extensionPath}`
],
slowMo: 50
});
page = await browser.newPage();
await page.goto('chrome-extension://acdcddifhaiiiagbodmcnebcgdmlgdkl/popup/popup.html');
});
So it will run in Github Actions and locally as well.
Related
We launch our Electron-based app like so:
test.beforeAll(async() => {
electronApp = await _electron.launch({
args: [
path.join(__dirname, '../'),
'--disable-gpu',
'--whitelisted-ips=',
'--disable-dev-shm-usage',
]
});
...
It used to work. Now the tests fail with this error message:
electron.launch: Timeout 30000ms exceeded.
61 | createDefaultSettings();
62 |
> 63 | electronApp = await _electron.launch({
| ^
You can see the tests at https://github.com/rancher-sandbox/rancher-desktop . To reproduce:
Set up:
git clone https://github.com/rancher-sandbox/rancher-desktop.git
npm i
To reproduce:
npm run test:e2e
This might be related to the node issue on Monterey 12.3.1 that it is already running on the default port 5000.
Try disabling "Airplay receiver" like this post, it worked for me.
"System Preference" -> "Sharing" -> "Airplay receiver"
Why nodeJS is not working on macOS Monterey?
This Meteor code uses "puppeteer 8.0.0", "puppeteer-core 10.0.0", puppeteer-extra 3.1.18" and "puppeteer-extra-plugin-stealth 2.7.8", It gives this error:
Error: Could not find expected browser (chrome) locally. Run npm install to download the correct Chromium revision (884014).
Tried "npm install" for no avail. Reading up online, tried removing "puppeteer-core": "^10.0.0" from package.json dependencies for no avail.
Any help is much appriciated. Thanks
const puppeteer = require('puppeteer-extra');
const nameH = require('./NameH');
const puppeteerOptions = {
headless: true,
ignoreHTTPSErrors: true,
args: ['--no-sandbox', '--single-process', '--no-zygote', '--disable-setuid-sandbox']
}
let browser;
let pageNameH;
const init = async () => {
const StealthPlugin = require('puppeteer-extra-plugin-stealth');
console.log('1') //>>>>>>>>>>>> Prints 1
puppeteer.use(StealthPlugin());
console.log('2') //>>>>>>>>>>>> Prints 2
browser = await puppeteer.launch(puppeteerOptions);
console.log('3') //>>>>>>>>> DID NOT PRINT <<<<<<<<<<<<<<<
pageNameH = await browser.newPage();
console.log('4')
await pageNameH.setUserAgent('Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36');
await pageNameH.setViewport({ width: 1366, height: 768 });
await pageNameH.setRequestInterception(true);
blockResources(pageNameH);
}
const blockResources = page => {
page.on('request', (req) => {
if (req.resourceType() == 'stylesheet' || req.resourceType() == 'font' || req.resourceType() == 'image') {
req.abort();
}
else {
req.continue();
}
});
}
export const abc = async (nm, loc) => {
try {
console.log('name try') //>>>>>>>>>>>> Prints "name try"
if (!(browser && pageNameH))
await init();
//use "required" nameh here
} catch (error) { // print the error <<<<<<<<<<<<<<<<<<<<<<<<<
console.log("Could not launch Puppeteer or open a new page.\n" + error);
if (browser && browser.close === 'function') await browser.close();
}
}
// included in package.json
"dependencies": {
"#babel/runtime": "^7.11.2",
"axios": "^0.21.1",
"check": "^1.0.0",
"cheerio": "^1.0.0-rc.6",
"jquery": "^3.5.1",
"meteor-node-stubs": "^1.0.1",
"nightmare": "^3.0.2",
"pending-xhr-puppeteer": "^2.3.3",
"puppeteer": "^8.0.0",
"puppeteer-core": "^10.0.0",
"puppeteer-extra": "^3.1.18",
"puppeteer-extra-plugin-adblocker": "^2.11.11",
"puppeteer-extra-plugin-block-resources": "^2.2.9",
"puppeteer-extra-plugin-stealth": "^2.7.8"
},
may be you can try this, it works for me on linux(centOS), puppeteer(10.2.0).
cd ./node_modules/puppeteer
npm run install
If that fails, you can also try running:
cd ./node_modules/puppeteer
npm install
This will download the chromium to ./node_modules/puppeteer/.local-chromium
I had the same problem. I checked my env variables, and even though PUPPETEER_SKIP_CHROMIUM_DOWNLOAD was set to false, it was still not working. After I removed the variable (unset PUPPETEER_SKIP_CHROMIUM_DOWNLOAD for mac), it worked.
related dependancies:
"dependencies": {
"chrome-aws-lambda": "^10.0.0",
"puppeteer-core": "^10.0.0",
},
"devDependencies": {
"puppeteer": "^10.0.0",
}
Launching Chromium:
import chromium from "chrome-aws-lambda";
const browser = await chromium.puppeteer.launch({
executablePath: await chromium.executablePath,
});
Fixed it by running this command to install chromium manually.
node node_modules/puppeteer/install.js
if you are testing locally, make sure you have puppeteer installed as dev dependencies. specifically
npm install puppeteer --save-dev
https://github.com/alixaxel/chrome-aws-lambda/wiki/HOWTO:-Local-Development#workaround
this approach allows us to rely on puppeteer for local development and puppeteer-core for production deployments.
I had the same issue. What worked for me was to specify as the executablePath Puppeteer launch option the fullpath to the local chromium used by Puppeteer.
Something like this:
const launchOptions = {
// other options (headless, args, etc)
executablePath: '/home/jack/repos/my-repo/node_modules/puppeteer/.local-chromium/linux-901912/chrome-linux/chrome'
}
As noted in another answer, it seems that also referencing a chromium local binary would work, but I think it's a worse solution, since Puppeteer is guaranteed to work only with the local bundled version of Chromium.
Throwing my answer in, in hopes that it helps someone not waste their entire evening like I did.
I was writing a Typescript server that used Puppeteer, and I'm using ESBuild to transpile from TS to JS. In the build step, esbuild was trying to bundle everything into one file, but I had to instruct it to preserve the Puppeteer import from node_modules.
I did this by marking puppeteer as external. See docs here.
Since npm i downloads a compatible version of chromium to the node_modules folder, once I preserved this import, it was able to find Chromium in the node_modules folder.
My build file looks like:
require("esbuild").buildSync({
entryPoints: ["src/index.ts"],
outdir: "build",
bundle: true,
platform: "node",
target: "node16",
external: ["puppeteer"],
});
And I run it with node prod-build.js.
Now in my code, I can just call launch!
const browser = await puppeteer.launch()
I used the installed version on my pc (maybe not what you're looking for)
const browser = await puppeteer.launch({headless:false, executablePath:
'C:/Program Files/.../chrome.exe' });
You may need to install some dependencies depending on your OS. Check Puppeteer's Troubleshooting page for more details.
I was having this error too and I noticed that I started getting such an error after updating my node from my Dockerfile to version ^16 (my puppeteer is in a container). How did I solve it? I downgraded my node from Dockerfile to version 12.
Hope this resolves it...
OBS: I use Ubuntu 21.04 in machine.
EDIT ------
In newest versions of node, you need to go in ./node_modules/puppeteer and run command npm install, then the correct packages will be installed.
I'm using that solution.
If you are using puppeteer in AWS SAM and you don't have puppeteer in dependencies, you can install the same in puppeteer-core using
node node_modules/puppeteer/install.js
For this setup to work you will have to add chrome-aws-lambda in the devDependencies.
"devDependencies": {
"chrome-aws-lambda": "^10.1.0"
}
Also before you take it to production don't forget to add the layer in your template.yaml file:
Layers:
- !Sub 'arn:aws:lambda:ap-south-1:764866452798:layer:chrome-aws-lambda:25'
I used mongodb-memory-server to test some repository functions in mongo, and run my unit-test at my local machine successfully, however when this code was pushed into GitHub, it was running fail. I am not sure the issue is about docker config or about mongodb-memory-server version.
Here is the log from GitHub:
9W45p5LM91Vj","tmpDir":{"name":"/tmp/mongo-mem--188-9W45p5LM91Vj"},"uri":"mongodb://127.0.0.1:42823/d791a878-09ac-4ccc-896d-ea603e2676ad?"}
2021-06-05T09:45:33.351Z MongoMS:MongoBinary MongoBinary options: {
"downloadDir": "/__w/son-git-test/son-git-test/node_modules/.cache/mongodb-memory-server/mongodb-binaries",
"platform": "linux",
"arch": "x64",
"version": "4.2.8",
"checkMD5": false
}
2021-06-05T09:45:33.356Z MongoMS:getos Trying LSB-Release
2021-06-05T09:45:33.372Z MongoMS:getos Trying OS-Release
2021-06-05T09:45:33.375Z MongoMS:MongoBinaryDownloadUrl Using "mongodb-linux-x86_64-debian92-4.2.8.tgz" as the Archive String
2021-06-05T09:45:33.375Z MongoMS:MongoBinaryDownloadUrl Using "https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-ubuntu1804-4.2.8.tgz" as the Download-URL
2021-06-05T09:45:33.377Z MongoMS:MongoBinaryDownload Downloading: "https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-ubuntu1804-4.2.8.tgz"
2021-06-05T09:45:33.377Z MongoMS:MongoBinaryDownload trying to download https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-ubuntu1804-4.2.8.tgz
2021-06-05T09:45:34.756Z MongoMS:MongoBinaryDownload moved /__w/son-git-test/son-git-test/node_modules/.cache/mongodb-memory-server/mongodb-binaries/mongodb-linux-x86_64-ubuntu1804-4.2.8.tgz.downloading to /__w/son-git-test/son-git-test/node_modules/.cache/mongodb-memory-server/mongodb-binaries/mongodb-linux-x86_64-ubuntu1804-4.2.8.tgz
2021-06-05T09:45:34.757Z MongoMS:MongoBinaryDownload extract(): /__w/son-git-test/son-git-test/node_modules/.cache/mongodb-memory-server/mongodb-binaries/4.2.8
2021-06-05T09:45:37.293Z MongoMS:MongoBinary MongoBinary: Download lock removed
2021-06-05T09:45:37.294Z MongoMS:MongoBinary MongoBinary: Mongod binary path: "/__w/son-git-test/son-git-test/node_modules/.cache/mongodb-memory-server/mongodb-binaries/4.2.8/mongod"
2021-06-05T09:45:37.309Z MongoMS:MongoInstance Mongo[42823]: Called MongoInstance._launchKiller(parent: 188, child: 203):
2021-06-05T09:45:37.323Z MongoMS:MongoInstance Mongo[42823]: STDERR: /__w/son-git-test/son-git-test/node_modules/.cache/mongodb-memory-server/mongodb-binaries/4.2.8/mongod: error while loading shared libraries: libcurl.so.4: cannot open shared object file: No such file or directory
2021-06-05T09:45:37.324Z MongoMS:MongoInstance Mongo[42823]: Mongod instance closed with an non-0 code!
2021-06-05T09:45:37.324Z MongoMS:MongoInstance Mongo[42823]: CLOSE: 127
2021-06-05T09:45:37.325Z MongoMS:MongoInstance Mongo[42823]: MongodbInstance: Instance has failed: Mongod instance closed with code "127"
2021-06-05T09:45:37.331Z MongoMS:MongoMemoryServer Called MongoMemoryServer.stop() method
2021-06-05T09:45:37.331Z MongoMS:MongoMemoryServer Called MongoMemoryServer.ensureInstance() method
2021-06-05T09:45:37.349Z MongoMS:MongoInstance Mongo[42823]: [MongoKiller]: exit - [null,"SIGTERM"]
FAIL src/squid/squid.controller.spec.ts (9.945 s)
● Console
console.log
before each
at Object.<anonymous> (squid/squid.controller.spec.ts:19:13)
console.log
Downloading MongoDB 4.2.8: 0 % (0mb / 126.5mb)
at MongoBinaryDownload.Object.<anonymous>.MongoBinaryDownload.printDownloadProgress (../node_modules/mongodb-memory-server-core/src/util/MongoBinaryDownload.ts:424:15)
● SquidController › should be defined
Failed: "Mongod instance closed with code \"127\""
16 | let controller: SquidController;
17 |
> 18 | beforeEach(async () => {
| ^
19 | console.log('before each');
20 | const module: TestingModule = await Test.createTestingModule({
21 | imports: [
at Env.beforeEach (../node_modules/jest-jasmine2/build/jasmineAsyncInstall.js:46:24)
at Suite.<anonymous> (squid/squid.controller.spec.ts:18:3)
at Object.<anonymous> (squid/squid.controller.spec.ts:15:1)
and here is gitflow config:
name: Code quality
on:
pull_request:
branches:
- develop
push:
branches:
- develop
defaults:
run:
shell: bash
jobs:
Code-Quality:
name: Code quality
runs-on: ubuntu-latest
container: node:lts-slim
steps:
- uses: actions/checkout#v2
- name: Install dependency
run: yarn install --frozen-lockfile
- name: Check lint and format
run: |
yarn format:check
yarn lint:check
- name: checking unit test
run: yarn test
and here is unit test code:
import { Test, TestingModule } from '#nestjs/testing';
import { MongooseModule } from '#nestjs/mongoose';
import { SquidController } from './squid.controller';
import { SquidService } from './squid.service';
import {
closeInMongodConnection,
rootMongooseTestModule,
} from '../test-utils/mongo/MongooseTestModule';
import { SquidSchema } from './model/squid.schema';
// May require additional time for downloading MongoDB binaries
jasmine.DEFAULT_TIMEOUT_INTERVAL = 600000;
describe('SquidController', () => {
let controller: SquidController;
beforeEach(async () => {
console.log('before each');
const module: TestingModule = await Test.createTestingModule({
imports: [
rootMongooseTestModule(),
MongooseModule.forFeature([{ name: 'Squid', schema: SquidSchema }]),
],
controllers: [SquidController],
providers: [SquidService],
}).compile();
controller = module.get<SquidController>(SquidController);
});
it('should be defined', () => {
expect(controller).toBeDefined();
});
afterAll(async () => {
await closeInMongodConnection();
});
});
After searching I found where the problem is. This issue is related to Node version. Mongo haven't had build version for Node slim/alpine.
We can fix by update node images: (container: node:14.17.0)
name: Code quality
on:
pull_request:
branches:
- develop
push:
branches:
- develop
defaults:
run:
shell: bash
jobs:
Code-Quality:
name: Code quality
runs-on: ubuntu-latest
container: node:14.17.0
steps:
- uses: actions/checkout#v2
- name: Install dependency
run: yarn install --frozen-lockfile
- name: Check lint and format
run: |
yarn format:check
yarn lint:check
- name: checking unit test
run: yarn test
I was able to successfully download a file with puppeteer, but it was just saving it to my /Downloads folder. I've been looking around and can't find anything in the api or forums to set this location.
My downloads are basically just go going to the link:
await page.goto(url);
Update for newer Puppeteer versions (~June 2022):
As mentioned by #Daniel here, you have to create the CDP session yourself:
const client = await page.target().createCDPSession()
await client.send('Page.setDownloadBehavior', {
behavior: 'allow',
downloadPath: './myAwesomeDownloadFolder',
})
Original Answer
This is how you can set the download path in latest puppeteer v0.13.
await page._client.send('Page.setDownloadBehavior', {behavior: 'allow', downloadPath: './myAwesomeDownloadFolder'});
The behaviour is experimental, it might be removed, modified, or changed later.
Pst, you can try more tricks listed here, on your own risk :).
In newer versions of Puppeteer (I'm using v14.1), the Accepted Answer no longer works:
await page._client.send('Page.setDownloadBehavior', {behavior: 'allow', downloadPath: './myAwesomeDownloadFolder'});
> TypeError: page._client.send is not a function
Instead, I had to explicitely create a new CDPSession:
const client = await page.target().createCDPSession()
await client.send('Page.setDownloadBehavior', {
behavior: 'allow',
downloadPath: './myAwesomeDownloadFolder',
})
I realize this is an old thread, but this thread popped up first for me when looking for how to set Puppeteer default download location.
I was able to set the download location using the following code,
let customChrome = path.resolve(__dirname, './customChrome')
let prefs = fs.readFileSync(customChrome+'/Default/Preferences');
let obj = JSON.parse(prefs);
obj.savefile.default_directory = path.resolve(__dirname, './downloads');
obj.download.default_directory = path.resolve(__dirname, './downloads');
fs.writeFileSync(customChrome+'/Default/Preferences', JSON.stringify(obj));
const browser = await puppeteer.launch({
userDataDir:customChrome,
headless: false,
args:['--disable-features=site-per-process','--no-sandbox']
});
This will set the default download directory for files before the process starts. Essentially, Puppeteer creates a custom profile each time it runs, we can override that profile and define the download directory.
The first time you run the above code, you will have to comment out the fs.readFile to fs.writeFile as the UserDirDirectory is created if it does not exist the first time that Chrome is started.
All profile related data is then stored in the customChrome/Default folder.
How to pass userDataDir profile folder to Puppeteer
All given solutions weren't working for me in the newer version of puppeteer 15.5.0
using puppeteer-extra with puppeteer-extra-plugin-user-preferences plugin did the trick.
// make sure puppeteer-extra & puppeteer-extra-plugin-user-preferences are installed
const UserPreferencesPlugin = require("puppeteer-extra-plugin-user-preferences");
const downloadImageDirectoryPath = process.cwd()
puppeteer.use(
UserPreferencesPlugin({
userPrefs: {
download: {
prompt_for_download: false,
open_pdf_in_system_reader: true,
default_directory: downloadImageDirectoryPath,
},
plugins: {
always_open_pdf_externally: true,
},
},
})
);
The answer from Muhammad Uzair solved my similar issue of setting the Chromium user preference to enforce PDF file downloads, but I ran into an issue of setting things up since I am using Puppeteer, Jest, and Jest-Puppeteer, where Jest-Puppeteer handles the initial setup behind the scenes.
This Github post from Macil helped with how to apply the puppeteer-extra-plugin-user-preferences plugin within the jest-puppeteer.config.js file.
For example, this is my jest-puppeteer.config.js file:
const puppeteer = require('puppeteer-extra');
const UserPreferencesPlugin = require('puppeteer-extra-plugin-user-preferences');
const userPreferenceOptions = {
userPrefs: {
plugins: {
always_open_pdf_externally: true,
},
download: {
open_pdf_in_system_reader: false,
prompt_for_download: false,
},
}
};
puppeteer.use(UserPreferencesPlugin(userPreferenceOptions));
require.cache[require.resolve('puppeteer')] = require.cache[require.resolve('puppeteer-extra')];
module.exports = {
launch: {
// https://github.com/puppeteer/puppeteer/blob/v13.3.2/docs/api.md#puppeteerlaunchoptions
headless: true, // opens a browser instance
slowMo: 25, // millis to slow each step
devtools: false, // auto opens the devtools in the browser
defaultViewport: {
width: 1820,
height: 980,
deviceScaleFactor: 1,
isMobile: false,
isLandscape: true,
},
product: "chrome", // can also specify firefox
browserContext: 'incognito',
args: [
// Chromium browser arguments: https://peter.sh/experiments/chromium-command-line-switches/
'--ignore-certificate-errors',
'--no-sandbox',
'--disable-setuid-sandbox',
'--window-size=1920,1080',
],
},
};
Finally, I run the program in docker container with chrome installed
FROM node:18-slim
# ------------------------------------------
# install extension
# ------------------------------------------
RUN apt-get update -y && apt-get install -y \
# chromium \
# libnss3 lsb-release xdg-utils wget \
wget gnupg \
&& wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add - \
&& sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list' \
&& apt-get update \
&& apt-get install -y google-chrome-stable fonts-ipafont-gothic fonts-wqy-zenhei fonts-thai-tlwg fonts-kacst fonts-freefont-ttf libxss1 \
--no-install-recommends \
&& rm -rf /var/lib/apt/lists/*
# ------------------------------------------
# set global config
# ------------------------------------------
ENV TZ Asia/Hong_Kong
# ------------------------------------------
# change the work directory
# ------------------------------------------
COPY source /root/source
WORKDIR /root/source
# ------------------------------------------
# upgrade npm
# ------------------------------------------
RUN npm install npm -g
RUN npm upgrade
# install node packages
RUN if test -e package-lock.json ; then npm ci ; else npm i ; fi
RUN npm run build
ENTRYPOINT ["npm", "run"]
CMD ["start"]
and
use await page.target().createCDPSession() as client for downloading the file
(
ref:
https://github.com/puppeteer/puppeteer/issues/1478#issuecomment-358826932
https://pptr.dev/api/puppeteer.cdpsession
)
const downloadPath = `[YOU OWN DOWNLOAD PATH]`
const browser = await puppeteer.launch({
headless: true,
args: ['--no-sandbox', '--disable-setuid-sandbox'],
executablePath: '/usr/bin/google-chrome-stable'
})
const page = await browser.newPage()
const client = await page.target().createCDPSession()
await client.send('Page.setDownloadBehavior', {
behavior: 'allow',
downloadPath
})
Update 30-07-2022:
An update has been made and this feature has been removed from previous versions of the package as well, if you have downloaded the package before 10-06-2022 it should work. For me it is like that, but it is puzzling why also previous versions were changed ..
I have manjaro linux and I installed nodejs and npm from official repositories
node version: v6.2.1
npm version: 3.9.5
gulp.task('inject', ['scripts', 'styles'], function () {
var injectStyles = gulp.src([
path.join(conf.paths.tmp, '/serve/app/**/*.css'),
path.join('!' + conf.paths.tmp, '/serve/app/vendor.css')
], { read: false });
var injectScripts = gulp.src([
path.join(conf.paths.src, '/app/**/*.module.js'),
path.join(conf.paths.src, '/app/**/*.js'),
path.join('!' + conf.paths.src, '/app/**/*.spec.js'),
path.join('!' + conf.paths.src, '/app/**/*.mock.js'),
])
.pipe($.angularFilesort()).on('error', conf.errorHandler('AngularFilesort'));
var injectOptions = {
ignorePath: [conf.paths.src, path.join(conf.paths.tmp, '/serve')],
addRootSlash: false
};
return gulp.src(path.join(conf.paths.src, '/*.html'))
.pipe($.inject(injectStyles, injectOptions))
.pipe($.inject(injectScripts, injectOptions))
.pipe(wiredep(_.extend({}, conf.wiredep)))
.pipe(gulp.dest(path.join(conf.paths.tmp, '/serve')));
});
When I run:
$ gulp serve
It display me:
[21:36:37] Using gulpfile /home/jics/Documents/Proyect/gulpfile.js
[21:36:37] Starting 'config'...
[21:36:37] Starting 'styles'...
[21:36:37] Finished 'config' after 236 ms
[21:36:37] Starting 'scripts'...
[21:36:37] gulp-inject 30 files into index.scss.
[21:36:39] Finished 'styles' after 2.36 s
[21:36:40] all files 211.97 kB
[21:36:40] Finished 'scripts' after 2.84 s
[21:36:40] Starting 'inject'...
[21:36:40] gulp-inject 1 files into index.html.
Segmentation fault
My coredumctl display me:
PID: 29909 (gulp)
UID: 1000 (jics)
GID: 1000 (jics)
Signal: 11 (SEGV)
Timestamp: lun 2016-06-13 18:03:49 CLT (3h 37min ago)
Command Line: gulp
Executable: /usr/bin/node
Control Group: /user.slice/user-1000.slice/session-c2.scope
Unit: session-c2.scope
Slice: user-1000.slice
Session: c2
Owner UID: 1000 (jics)
Boot ID: 857cb1e6f9134beb91d172fc85f05f36
Machine ID: 50f47fe8f80b4f92829b61933e8b309e
Hostname: jics-pc
Coredump: /var/lib/systemd/coredump/core.gulp.1000.857cb1e6f9134beb91d172fc85f05f36.29909.1465
Message: Process 29909 (gulp) of user 1000 dumped core.
Stack trace of thread 29909:
#0 0x00002080c7ca188c n/a (n/a)
The only why I can run gulp serve with success is deleting de follow line from de configuration file .pipe($.inject(injectScripts, injectOptions))
Well I did do it with n
$ sudo npm install -g n
$ sudo n stable
install : node-v6.2.1
mkdir : /usr/local/n/versions/node/6.2.1
fetch : https://nodejs.org/dist/v6.2.1/node-v6.2.1-linux-x64.tar.gz
######################################################################## 100,0%
installed : v6.2.1
Finally I do $ gulp serve and run perfectly