Puppeteer: Download Chromium for different platforms - electron

I'm building a UI-automator with Puppeteer and I'm shipping it as a Electron-packaged app. It works nice-and-smooth except for this issue:
Chromium is not downloaded exception is thrown when the app is executed on a platform different than the one the app has been packaged on.
Better said, I'm developing on a Linux environment and I'm packaging my app for both Linux and Windows, Linux app works fine, Windows app doesn't.
The problem is: Chromium is downloaded at npm install time, and it's done selectively based on the current platform. Being current platform Linux, this very version of Chromium is then shipped regardlessly on every platform's app.
I should be able to do one of the following:
Download all-platform Chromium when npm install (on dev machine)
Download Chromium selectively at packaging time (still on dev machine)
Force my users to download Chromium at runtime (at first usage for example)
The problem is I haven't found any Puppeteer configuration I can use for such purpose.
Thanks

The Chromium download is done by node_modules/puppeteer/install.js during npm install. You could call this code from your application's build scripts. For example:
const Downloader = require('puppeteer/lib/Downloader');
const revision = require('puppeteer/package').puppeteer.chromium_revision;
Downloader.createDefault().downloadRevision('win64', revision, () => undefined)
.then(() => { console.log('Done!') })
.catch(err => { console.log('Error', err) })

An update to #Pasi's answer, the following works for "puppeteer": "^1.15.0"
const puppeteer = require('puppeteer');
const browserFetcher = puppeteer.createBrowserFetcher({ platform: 'win64' });
const revision = require('puppeteer/package').puppeteer.chromium_revision;
browserFetcher.download(revision)
.then(() => console.log('Done'))
.catch(error => console.log('Error', error))

Related

React Native - .ENVs are undefined in Metro Bundler's config file when bundling iOS apps

I have NPM scripts that build and run our app with mocked backend data (used for component testing). They set ENVs inline using the cross-env npm package.
"android-mock": "cross-env MOCK_BACKEND=1 NODE_ENV=development node generate-config.js && react-native run-android -- --reset-cache", - emulator runs on Windows
"ios-mock": "cross-env MOCK_BACKEND=1 NODE_ENV=development node generate-config.js && react-native run-ios -- --reset-cache", - simulator runs on MacOS
Metro bundler looks for the MOCK_BACKEND env and based on that, it resolves paths so that the app uses mocked data instead of relying on the backend to get it.
Problem: Metro can read the process.env.MOCK_BACKEND value only when bundling Android apps, on iOS, the value returns undefined.
What is the correct way to define ENVs so that Metro can read them properly also for iOS bundling?
I don't know why, but it seems like Metro overwrites set ENVs when bundling iOS apps.
Elsewhere ENVs are defined.
If anyone comes over this problem, this is how I solved it.
Solution
1. In the generate-config.js script that is in NPM scrips above, I have added NODE_ENV checks. The script generates the config.js inside the public folder, based on NODE_ENV.
const fs = require("fs");
console.log( process.env.NODE_ENV);
if(process.env.NODE_ENV === 'production'){
fs.copyFile("config.runtime.js","public/config.js",(err) => {if(!err){console.log(err)}});
} else if (process.env.NODE_ENV === 'mock'){
fs.copyFile("config.mock.js","public/config.js",(err) => {if(!err){console.log(err)}});
} else {
fs.copyFile("config.debug.js","public/config.js",(err) =>{if(!err){console.log(err)}});
}
2. I have imported generated config.js into Metro.config and used it as needed.
const config = require(path.resolve(__dirname, 'public/config.js'));
config.js for reference:
module.exports = {
isProduction : false,
disableCache: true,
API:"http://alanj.bs.local:15455/",
/////////////////////////////////////
// ENVs
/////////////////////////////////////
MOCKED_BACKEND: 1,
/////////////////////////////////////
}
We ran into the same issue, we have no solution yet but interesting observations after approximately 1 day of trial and error:
Start Packager Script
The 'Start Packager' script in Xcode is responsible for the mess.
It does not pass the environment variables to the packager.
The problem lies within Mac OS open:
Create a new file /tmp/test.command:
#!/bin/bash
echo "Environment Variable XXX='$XXX'"
Now use
XXX="visible" /tmp/test.command
This will print
Environment Variable XXX='visible'
Whereas when called with open:
XXX="not visible" open /tmp/test.command
will just yield:
Environment Variable XXX=''
Even with
XXX="not visible" open --env XXX="abc" /tmp/test.command
we just get:
Environment Variable XXX=''
Not sure if we should file a support ticket at Apple

How to solve error "Firefox can’t find the file at moz-extension://......" when running a built blank Quasar BEX ("quasar dev -m bex" works)

These are the commands I ran (I didn't change the code in any way):
quasar upgrade -i
mkdir folder
cd folder
quasar create
quasar mode add bex
npm i
quasar build -m bex
cd /dist/bex/UnPackaged && web-ext sign --api-key ... --api-secret ...
I then drag&dropped that signed .xpi file (in the folder ./web-ext-artifacts/) into the latest Firefox ESR in Debian 10 stable (78.12.0esr) and installed the addon (with no other addons being installed/running in that Firefox profile). When I click onto the Quasar (v2.0.1) icon in the upper right of Firefox after it finished installing it shows this error page:
File not found Firefox can’t find the file at moz-extension://extension-id/www/index.html.
instead of the proper Vue/Quasar page. The same also occurs with the unsigned addon (after setting xpinstall.signatures.required to enable installation) but it does work fine when running quasar dev -m bex.
Why is that and how to solve it?
It appears to be due to problems with the filepaths when using the build-command rather than the dev command. One can change the url in address bar to show the page but neither could I change all places where 'index.html' or process.env.DEV is used to make it work, nor would that be the build-process as is which I assume ought to work (as is; as said I only ran those few commands for a completely blank BEX and didn't change the code for testing).
Seems like this is bug since quasar: 2.0.0-beta.1 moved to stable:
This is not a good long term solution, but I did the following as a temporary fix:
install execa
npm i execa
in quasar.conf.js
const execa = require('execa')
...
build: {
async afterBuild(cfg) {
try {
// bit of a hack to move the index.html into the www folder on build of Packaged
const dirUnPackaged = cfg.quasarConf.bex.builder.directories.input
const { stdout } = await execa('mv', [`${dirUnPackaged}/index.html`, `${dirUnPackaged}/www/`])
console.log(stdout)
} catch (error) {
console.error(error.message)
}
},
}
Essentially moving the index.html file into the www folder in the Package

exiftool-vendored doesn't return when used in an electron app on Mac?

On Mac, when I run my app from WebStorm, exiftool-vendored works great. However, when I build my app (I use electron-builder) and install it on the same Mac, it never returns, even just trying to get the version:
exiftool.version().then(version => writeBreadcrumb('exif', version))
In other words, no error is raised, and the then is never executed when running an installed version of my app, though it works fine running my app from WebStorm (with cd build && electron .)
What am I doing wrong? Is there an example anywhere of how to use exiftool-vendored in an electron app?
You should take a look at what the docs say about making it work with Electron:
How do you make this work with electron?
Electron is notoriously brittle and buggy, and is not officially supported by this package. Although PhotoStructure uses this package within electron, there's a nontrivial amount of auxiliary support code specific to that project to make it work smoothly.
If you're still anxious to try, here are some things to keep in mind:
Note that this package will spawn exiftool external processes, which means the exiftool-vendored.pl and exiftool-vendored.exe packages should be included in your asarUnpack. SmartUnpack might work, but if it doesn't use a pattern like node_modules/{exiftool-vendored.*}/**/*.
If you're requiring exiftool-vendored from within a webview, you're gonna have a bad time. Many things won't work due to a lack of node compatibility within electron.
__dirname at runtime from within an asar package after webpacking will be invalid, so don't rely on that.
— https://github.com/photostructure/exiftool-vendored.js/wiki/FAQ#how-do-you-make-this-work-with-electron
Since I never found a way to get exiftool-vendored to work with electron on Mac, I accepted the above answer, as essentially a warning to steer clear of exiftool-vendored for electron on Mac.
This answer is included for completeness, for those of us who need exiftool in an electron app for both Mac and Windows:
I used node-exiftool with these settings added in package.json for electron-builder:
"build": {
...
"win": {
...
"extraResources": "exiftoolwin/**/*"
},
"mac": {
...
"extraResources": "exiftool/**/*"
}
}
In the root of my project, I added folders exiftoolwin and exiftool. In exiftoolwin, I put exiftool.exe which I obtained by following the Windows Stand-Alone Executable instructions here, and in my exiftool folder I put exiftool and lib which I obtained by extracting the full perl distribution on Mac, as described on the same page.
Then, in my .jsx (I'm using React):
import exiftool from 'node-exiftool';
const exiftoolFolderAndFile = process.platform === 'win32' ? 'exiftoolwin/exiftool.exe' : 'exiftool/exiftool';
const exiftoolPath = path.resolve(__dirname, '../..', exiftoolFolderAndFile);
const ep = new exiftool.ExiftoolProcess(exiftoolPath);
Then I just use ep as described here.
This is working for us:
add this dependency:
"exiftool-vendored": "^15.2.0",
Update package.json "build" section for mac ( not needed for windows as far as we can see )
"build": {
"mac": {
...
"asarUnpack": [
"node_modules/exiftool-vendored/**" ,
"node_modules/exiftool-vendored.pl/**"
]
}
}

electron-builder package for windows in dev mode

I need to test my app on windows, but I am using a mac. It is very easy to package the app to run on windows, but I cannot package the app in dev-mode. I am using electron-is-dev to decide if I am running in dev or not. I need to run my tests on windows because I am testing a very specific windows hardware functionality. I don't want to comment my if(isDev){doSomething} just to run these test, and then uncomment it before I push the change. I was hoping there is some flag I can set in the electron-build cli, or maybe run electon . -windows?
Parse the parameter by adding sample code below to your electron main.js
const args = process.argv.slice(1);
windows = args.some(val => val === '-windows');
It can still be parsed on electron executable app by running in cmd like "electronapp.exe -windows"
The best way to do this so as to use the IsDev is to add the ELECTRON_IS_DEV environment variable to the app kinda like #carlokid suggested. I used: https://stackoverflow.com/a/34769146/3966009. This is the target I used for my app:
C:\Windows\System32\cmd.exe /c "SET ELECTRON_IS_DEV=1 && START ^"^" ^"C:\Program Files (x86)\My App\Fun Time.exe^""

How to setup Appium Environment for Android Automation?

I am working as SD in Test. I am new to Appium Automation tool, this tool is very tricky to set up environment for me.
I referred following link: http://unmesh.me/category/appium/
This link helped me to install Node.js and appium through command line. But I am not sure this right way to do.
I got following message from command line :
mani-kandans-MacBook-Pro:platform-tools manikandan$ info: Welcome to Appium v0.8.2 (REV e9cc66197ad6a3496322bd77a8699509fc761b69)
info: Appium REST http interface listener started on 0.0.0.0:4723
info - socket.io started
After this I don't have any idea. How to write testcase and run it through Appium?
If your interest to share your knowledge about Appium tool. Please guide me.
How to Install Appium?
How to run testcase through Appium tool?
Part One:-. You appear to have launched the appium server using node server.js
- You can check the server by going to localhost:4723/wd/hub/status in your browser this will return a few details of the server. You have already done this.
The command output will look like this confirming that the server is started:
info: Welcome to Appium v0.8.1 (REV ***********************************)
info: Appium REST http interface listener started on 0.0.0.0:4723
info - socket.io started
Part Two:-. Next you use the selenium RC for Python, Java, or c# or whatever your language choice. I used c# and can provide examples this should be similar for your tests.
To add the selenium to a c# class: using OpenQA.Selenium.Remote;
You pass all your data to a selenium desired capabilities object.
Some custom desired capabilities exist such as:
'app-package' this is the app package name such as com.myapp.main,
'app-activity' which is the apps main activity to be called which will also launch the app. This is often a splash activity or main activity,
'wait-activity' is the activity that Appium will check for once launched, this would be the app-activity but for me it is different if for some tests a new activity is launched than is called,
'version' taking the android version,
'device ID' taking your attached device or AVD to command and app which will have a local path to the apk you wish to install. This is signed and installed on start-up if a resigned app already exists it will skip this for you.
DesiredCapabilities caps = new DesiredCapabilities();
caps.SetCapability("app-package", "com.myapp.test");
caps.SetCapability("browserName", "");
caps.SetCapability("device", "Android");
caps.SetCapability("app-activity", "com.myapp.SplashActivity");
caps.SetCapability("takesScreenshot", true);
caps.SetCapability("version", "4.1.2");
caps.SetCapability("device ID", "uniquedeviceid");
caps.SetCapability("app", #"C:\path to\app\on\pc\app.apk");
Following the Capabilities you create create a remote web driver object passing the hub url that you've used e.g http://localhost:4723/wd/hub and the Desired Capabilities you've created.
RemoteWebDriver driver = new RemoteWebDriver(new Uri("http://localhost:4723/wd/hub/"), caps);
This line uses the ip or host of the Appium server to begin listening for requests.
For me this step signs installs and launches the app on the attached device hopefully this will work for you the same.
This is where the selenium tests you write are connected to the Appium server.
Now using the created driver object you can access the selenium rc commands of which Appium has implemented many alternatives for android testing.
During each of these your Appium server console window should show you if there is any issues.
Output will be colour coded to assist in identifying failures from this window but you can handle these your own way and output to a file if needed.
Update for multiple devices
I am unsure on the use of multiple devices, I would consider selenium grid my previous attempts to add 2 devices to one machine and test had confusion where adb was unable to distinguish regardless of the device id addition to the configuration and commands.
The Appium team have been making improvements to add grid functionality to the server, I recommend you have a look into Appium Grid (link updated)
I apologize for my lack the experience with grid to assist you further.
Regards, Brian
It seems to be late reply, but still I guess this post can help some one, who are looking for step by step by guide to install Appium on Windows platform
http://qaautomationworld.blogspot.in/2014/12/appium-setup-for-android-windows.html
This link mainly deals with the following sections
JDK Installation
Android SDK Installation path setup
Appium Installation
a) Using node.js
b) Using Appium.exe
Here's my env.rb file for appium android.
require 'rubygems'
require 'appium_lib'
# Start Android driver
apk = {
device: :android,
app_path: (true && ENV['apk']) || 'path to apk',
app_package: (true && ENV['package']) || 'com.foo.cam',
app_activity: (true && ENV['activity']) || '.SplashActivity',
app_wait_activity: (true && ENV['activity']) || '.MainActivity',
}
Appium::Driver.new(apk).start_driver
Appium.promote_appium_methods Object
log = Logger.new(STDOUT)
case ENV['log']
when 'WARN'
log.level = Logger::WARN
when 'DEBUG'
log.level = Logger::DEBUG
when 'INFO'
log.level = Logger::INFO
when 'ERROR'
log.level = Logger::ERROR
when 'FATAL'
log.level = Logger::FATAL
when 'UNKNOWN'
log.level = Logger::UNKNOWN
else
log.level = Logger::DEBUG
end
log.debug('starting suite')
Before do
#test_env = {
device: driver,
main_activity: (true && ENV['main_activity']) || 'grid.GridLoginActivity',
logger: log
}
end
# Optional--clears alerts
After ('#rate_limit') do |scenario|
log = #test_env[:logger]
device = #test_env[:device]
if scenario.failed?
begin
wait = Selenium::WebDriver::Wait.new :timeout => 1
wait.until { device.alert_accept }
log.debug('cleared rate limit dialog')
rescue
log.error("dialog didn't pop.")
end
end
log.debug('rate_limit finished')
end
After ('#network_connection') do |scenario|
log = #test_env[:logger]
device = #test_env[:device]
if scenario.failed?
begin
wait = Selenium::WebDriver::Wait.new :timeout => 1
wait.until { device.alert_accept }
log.debug('cleared network connection issue')
rescue
log.error("dialog didn't pop.")
end
end
log.debug('network_connection finished')
end
To install Appium first up all Download Required Tools:
Android Studio
Appium Jar Files For Java
Java Selenium Client Plugin
Appium Server
Java SDK
After downloading all these tools follow step by step process mention in this blog:
Installation Process of Appium in Android Studio
Here I have tried to explain full end to end set up instruction to Configure and run Android Mobile Automation Testcases using Appium
Download Java and set Java_Home in environmental variables
Download Android STUDIO from below link
https://developer.android.com/studio/index.html
Check Android installation path in Machine
Set Android_Home Environmental variables path to SDK location and include bin folder paths in PATH variable
Open Android Studio and configure Virtual device/Emulator
Open Emulator and check if it is working.
Download Node.js
https://nodejs.org/en/download/
Set Node_Home Environmental variables path
Set npm Environmental variables path
Download Appium Server from Node
Download Appium and Selenium Java client library
Install Eclipse – Create a Project in Eclipse - configure Appium libraries
Add All dependencies
//You can download any node module only using npm
npm install – g appium – Latest Stable release version 1.16.0 – Android 10+ version
npm uninstall -g appium // g stands for global
Appium – starts the server

Resources