A protractor spec running from a Jenkins job, that connects to SauceLabs. It clicks a button to download a PDF, and checks that the file successfully downloaded. I am unable to get the chrome browser to NOT open a "Save As" prompt using an absolute path. I AM able to avoid the "Save As" prompt if I use '~/Downloads' as filename, but then my browser.wait that waits for the file to exist hangs forever.
// spec.js
import fs from 'fs'
import path from 'path'
fs.mkdirSync('./downloads')
describe('Clicking DOWNLOAD button', () => {
it('should download a proposal', () => {
const filename = path.resolve(__dirname, './downloads/proposal.pdf')
if (fs.existsSync(filename)) {
fs.unlinkSync(filename)
}
page.downloadProposalBtn.click()
browser.wait(() => fs.existsSync(filename), 180000)
.then(() => {
expect(fs.existsSync(filename)).toBe(true)
})
}, 180000)
})
Below is the relevant portion of my conf file. I would expect the prompt_for_download setting to make the prompt not show, but it does..
// conf.js
capabilities: {
platform: 'macOS 10.12',
browserName: 'chrome',
version: '59.0',
screenResolution: '1400x1050',
chromeOptions: {
args: ['--no-sandbox', '--test-type=browser', 'disable-infobars=true'],
prefs: {
download: {
prompt_for_download: false,
directory_upgrade: true,
default_directory: path.resolve(__dirname, './downloads'),
},
credentials_enable_service: false,
},
},
},
Am I missing something? I feel like I might be misunderstanding where Saucelabs is running these tests from, but it would seem that given I fs.mkdir the ./downloads folder, then when I path.resolve it, that should work.
Unsure if this constitutes an "answer" but this is how I'm proceeding. After a lot of research I think that testing if a file downloaded on a remote VM (like SauceLabs) isn't possible. What I am doing instead is breaking the test into two parts:
Test the download button: click the button and assert that no error occurred
Make GET request to the underlying endpoint api/download that the button is using, write the response to a folder, and from there assert (using nodejs) that the file exists in my Jenkins project's workspace. This feels hacky, but given SauceLabs doesn't seem to give much access to the VM that the webdriver is running on, I don't see another way.
You will get the prompt, even though the option is set to "false" if the default download directory doesn't exist. "./downloads" is OSX syntax, which the chrome driver probably doesn't understand.
Try this instead:
default_directory: __dirname + '/downloads'
Related
I am newbie to service worker concept so forgive me if I am overlooking something from documentation. I have an angular application already running in production and I am trying to introduce service worker using sw-precache.
To start with I am trying to precache all images/fonts and couple of js files and see if it works, so my precache config is like this -
{
"cacheId": "static-cache",
"importScripts": [
"sw-toolbox.js"
],
"stripPrefix": "dist/",
"verbose": true,
"staticFileGlobs": [
"dist/img/**.*",
"dist/javascripts/require.js",
"dist/stylesheets/**.*",
"dist/webfonts/**.{ttf, eot, woff}",
"sw-toolbox.js",
"service-worker.js"
]
}
Now I can see service worker registered and installed properly and cache storage shows all the urls with _sw-precache hashes.
But when I load the application and see in network tab all static content are still served from memory/disk, not from service worker and I am unable to debug why is it so. Am I missing something here -
UPDATE:
More information: I had wrong configurations since I have dynamic url and server side rendered html. Server side it's test.jsp which is giving me initial shell.
For now I have removed all other static files from cache and kept only show.css
So update config now is -
{
"importScripts": [
"sw-toolbox.js"
],
"stripPrefix": "dist/",
"verbose": true,
"staticFileGlobs": [
"dist/stylesheets/show.css"
],
"dynamicUrlToDependencies": {
"/developers": ["dist/stylesheets/show.css"]
},
"navigateFallback": "/developers"
}
Web root folder is named differently and it is -
- dashboard
-- img
-- javascripts
-- service-worker.js
-- sw-toolbox.js
- test.jsp
And I see /developers url as an entry in storage cache, but still it's not served from service worker for next refresh. I have tried all my energy to fix this, but I desperately need some clue here, what's missing in here. TIA.
Let me know if need more info.
It seems that whitespaces in your file extension list are not allowed. Your definition for webfonts should be:
"dist/webfonts/**.{ttf,eot,woff}",
I cloned the sw-precache repo and added a unit test where I compared two generated files with two diffrent staticFileGlobs, one with whitespace and one without.
it('should handle multiple file extensions', function(done) {
var config = {
logger: NOOP,
staticFileGlobs: [
'test/data/one/*.{txt,rmd}'
],
stripPrefix: 'test'
};
var configPrime = {
logger: NOOP,
staticFileGlobs: [
'test/data/one/*.{txt, rmd}'
],
};
generate(config, function(error, responseString) {
assert.ifError(error);
generate(configPrime, function(error, responseStringPrime) {
assert.ifError(error);
console.log('responseStringPrime',responseString);
assert.strictEqual(responseString, responseStringPrime);
done();
});
});
});
and it failed. The second config didn't include the .rmd file:
-var precacheConfig = [["/data/one/a.rmd","0cc175b9c0f1b6a831c399e269772661"],["/data/one/a.txt","933222b19ff3e7ea5f65517ea1f7d57e"],["/data/one/c.txt","fa1f726044eed39debea9998ab700388"]];
versus
+var precacheConfig = [["test/data/one/a.txt","933222b19ff3e7ea5f65517ea1f7d57e"],["test/data/one/c.txt","fa1f726044eed39debea9998ab700388"]];
I am unable to use Composer and thus have to install CakePDF plugin manually, but following examples from official CakePHP documentation does not seem to work.
So here is installation flow that I have followed:
1.) Copied the plugin to app/plugins/CakePdf
2.) Updated the app's composer.json file, like following:
"autoload": {
"psr-4": {
"CakePdf\\": "./plugins/CakePdf/src",
"CakePdf\\Test\\": "./plugins/CakePdf/tests"
}
},
"autoload-dev": {
"psr-4": {
"App\\Test\\": "tests",
"Cake\\Test\\": "./vendor/cakephp/cakephp/tests"
"CakePdf\\": "./plugins/CakePdf/src",
"CakePdf\\Test\\": "./plugins/CakePdf/tests"
}
}
3.) Loaded the plugin in bootstrap.php:
Plugin::load('CakePdf', ['bootstrap' => true, 'routes' => true, 'autoload' => true]);
4.) Added router extensions:
Router::extensions(['pdf']);
5.) Tried a very simple sample from plugin's doc:
$cakePdf = new CakePdf(array(
'engine' => 'CakePdf.DomPdf',
'pageSize' => 'A4',
'orientation' => 'portrait'
));
$html = '<html><head><body><p>Pdftest</p></body></head></html>';
$rawPdf = $CakePdf->output($html);
However the code breaks at the first line and the following error message is provided:
Class 'App\Controller\CakePdf' not found
I would really appreciate any help or guidance for how a plugin should be installed manually.
If there is any other information that I need to provide, just ask.
You are getting this error because inside vendor/composer/ you can see some autoload_*.php files. These files hold the paths to load your classes. I think no one can safely tell you what to update and where in these files.
So you have two solutions:
1 - Copy composer.json on a local machine and run composer update. Then move the files created inside your app. I would suggest to take a backup before. Most probably the things that you will have to move are:
vendor/
composer.json
composer.lock
2 - Start updating the files inside vendor/composer/autoload_*.php with the paths from the plugin. Most probably you will only need to update the following two files:
vendor/cakephp-plugins.php and vendor/composer/autoload_psr4.php. Personally I wouldn't choose the second solution I am just adding it as an alternative just in case.
Hello!
I'm trying to take screenshots in protractor and browserstack, I've the following conf.js file:
var HtmlReporter = require('protractor-html-screenshot-reporter');
var reporter=new HtmlReporter({
baseDirectory: './protractor-result', // a location to store screen shots.
docTitle: 'Report Test Summary',
docName: 'protractor-tests-report.html'
});
// An example configuration file.
exports.config = {
// The address of a running selenium server.
seleniumAddress: 'http://hub.browserstack.com/wd/hub',
// Capabilities to be passed to the webdriver instance.
capabilities: {
'browserName': 'chrome',
'version': '22.0',
'browserstack.user' : 'user_name',
'browserstack.key' : 'user_key',
'browserstack.debug' : 'true'
},
// Spec patterns are relative to the current working directly when
// protractor is called.
specs: ['./specs/home_page_spec.js'],
// Options to be passed to Jasmine-node.
jasmineNodeOpts: {
showColors: true,
defaultTimeoutInterval: 30000
},
onPrepare: function() {
jasmine.getEnv().addReporter(reporter);
}
};
And the browserstack help says that I need to add the following lines:
var fs = require('fs');
webdriver.WebDriver.prototype.saveScreenshot = function(filename) {
return driver.takeScreenshot().then(function(data) {
fs.writeFile(filename, data.replace(/^data:image\/png;base64,/,''), 'base64', function(err) {
if(err) throw err;
});
})
};
driver.saveScreenshot('snapshot1.png');
Does any one could point me to where to add these lines? and how? (I'm also using PageObject pattern)
I think you are talking about two things, one is the plugin for making screenshots and the second is a creating screeshots manually within your test code regardless a plugin.
In theory, the plugin should make screenshots for you. If not you can create them manually with the code provided from browserstack, just put in anywhere in your test code after some expects.
Anyway, to make screenshots from protractor I recommend use protractor-screenshoter-plugin
(disclaimer: I am the author), also you can have a look at Protractor-Screenshots-Alernatives
Now in one of the branches I have a new support for parallelization. Have a look at https://github.com/azachar/protractor-screenshoter-plugin/tree/feat-parallel-support.
To install the unstable version that contains the parallelization support use
npm install azachar/protractor-screenshoter-plugin#feat-parallel-support
to install stable version without parallel support, just type as usual:
npm install protractor-screenshoter-plugin
Let me know if it works as expected!
Cheers,
Andrej
Problem
I'm testing downloading a file, but when I trigger the download, the "Save as..." prompt appears.
I saw a solution in this SO question but it doesn't seem to work for me.
Config
My protractor config file looks like this (coffeescript):
exports.config =
capabilities:
browserName: "chrome"
shardTestFiles: true
maxInstances: 2
chromeOptions:
args: ['--no-sandbox', '--test-type=browser']
prefs:
download:
prompt_for_download: false
default_directory: '/'
default_content_settings:
popups: 0
More
On chromeOptions.pref webdriver docs states:
See the 'Preferences' file in Chrome's user data directory for examples.
I can't actually see default_directory in my own Chrome preferences file.
"download": {
"directory_upgrade": true,
"prompt_for_download": false
},
System
Protractor: Version 1.5.0 (pretty new)
Node: 0.10.28, 0.11.8 and 0.11.14
Provide an absolute path to an existing directory in default_directory chrome preference.
For me, the Save As prompt was appearing when I mentioned a slash at last in the path for example: A:\Proj\Downloads\ & didn't see any prompt when mentioned without a slash at the end of the path i.e A:\Proj\Downloads
I want to use Paypal Adaptive Payments and Paypal Adaptive Accounts libs in my CakePHP 2.4.x application. I am loading them via composer. My composer.json file looks like this:
{
"require": {
"paypal/adaptivepayments-sdk-php":"v3.6.106",
"paypal/adaptiveaccounts-sdk-php":"v3.6.106"
},
"config": {
"vendor-dir": "Vendor"
}
}
Both libs contain Paypal/Types/Common/RequestEnvelope.php and for each lib they are different. I'm running into a conflict with this class name where the right one isn't being used. I believe the solution is to use autoload in my composer.json. I've read the documentation and don't believe I'm using it correctly. Here is what I'm attempting:
{
"require": {
"paypal/adaptivepayments-sdk-php":"v3.6.106",
"paypal/adaptiveaccounts-sdk-php":"v3.6.106"
},
"config": {
"vendor-dir": "Vendor"
},
"autoload": {
"psr-4": {
"AdaptivePaymentsLib\\": "Vendor/paypal/adaptivepayments-sdk-php/lib",
"AdaptiveAccountsLib\\": "Vendor/paypal/adaptiveaccounts-sdk-php/lib"
}
}
}
And in my controller I'm attempting to call RequestEnvelope like this:
$requestEnvelope = new AdaptivePaymentsLib\PayPal\Types\Common\RequestEnvelope("en_US");
It is not being found. Active Accounts was only recently added to the project. Previously getting the request envelope worked fine with $requestEnvelope = new PayPal\Types\Common\RequestEnvelope("en_US"); so it was only with the addition of the accounts which presented the conflict and caused the breakage.
You should not define autoloading for your dependencies - that is the task for them to solve.
If you look at the composer.json file for paypal/adaptivepayments-sdk-php, you see:
"autoload": {
"psr-0": {
"PayPal\\Service": "lib/",
"PayPal\\Types": "lib/"
}
}
If you look at the same file in paypal/adaptiveaccounts-sdk-php, you see:
"autoload": {
"psr-0": {
"PayPal\\Service": "lib/",
"PayPal\\Types": "lib/"
}
}
After installing, Composer creates a file vendor/composer/autoload_namespaces.php with this content:
return array(
'PayPal\\Types' => array($vendorDir . '/paypal/adaptivepayments-sdk-php/lib', $vendorDir . '/paypal/adaptiveaccounts-sdk-php/lib'),
'PayPal\\Service' => array($vendorDir . '/paypal/adaptivepayments-sdk-php/lib', $vendorDir . '/paypal/adaptiveaccounts-sdk-php/lib'),
'PayPal' => array($vendorDir . '/paypal/sdk-core-php/lib'),
);
So both libraries are included here, and I have no doubt the autoloading will work.
You cannot really do something about the duplicate classes with different content. Did you open an issue on Github? Without making the developer team aware of this problem, it will never get solved.
As a hack, you could define a post-install and post-update script that deletes one of these files. See the composer documentation for more details. Composer accepts either any shell command, or a static call to a PHP class. I'd go with the shell command here.