I try to build my React project with gulpfile.js in production mode so the query developer tools show green color in browser tab. However, it still failed with dead code elimination error, which means development version is still detected in react developer tools.
I have already tried many ways to eliminate this error. One of the closest solution is to add 'unreachable-branch-transform' and gulpif argv in browserify part in gulpfile.js. Please check gulpfile.js content below.
var gulp = require('gulp');
var imagemin = require('gulp-imagemin');
var clean = require('gulp-clean');
var argv = require('yargs').argv;
var gulpif = require('gulp-if');
var browserify = require('browserify');
var watchify = require('watchify');
var babelify = require('babelify');
var source = require('vinyl-source-stream');
var buffer = require('vinyl-buffer');
var envify = require('envify/custom');
var replace = require('gulp-replace');
var gutil = require('gulp-util');
var uglifyCSS = require('gulp-uglifycss');
var uglifyJS = require('gulp-uglify');
var version_append = require('gulp-version-append');
var connect = require('gulp-connect');
var historyApiFallback = require('connect-history-api-fallback');
var workboxBuild = require('workbox-build');
var prefixer = require('autoprefixer');
var postcss = require('gulp-postcss');
var concat = require('gulp-concat');
var less = require('gulp-less');
var chalk = require("chalk");
var path = require('path');
var exec = require('child_process').exec;
var paths = {
public_view_src : "view/",
public_view_dest : "public/",
images: 'img/**/*',
css :
[
"node_modules/bootstrap/dist/css/bootstrap.min.css",
"node_modules/font-awesome/css/font-awesome.min.css",
"node_modules/animate.css/animate.min.css",
"node_modules/lato-font/css/lato-font.min.css"
],
js :
{
plugins: [
"node_modules/clientjs/dist/client.min.js",
"node_modules/jquery.payment/lib/jquery.payment.min.js"
],
vendor: [
"node_modules/jquery/dist/jquery.min.js",
"node_modules/bootstrap/dist/js/bootstrap.min.js"
],
react : ["./src/app.js", "./src/**/*.js"],
app: "./script/*.js",
register_service_worker: 'service_worker/register_service_worker.js'
},
fonts : [
"node_modules/font-awesome/fonts/**/*",
"node_modules/bootstrap/dist/fonts/**/*"
],
less : ["less/style.less", "less/**/*.less", "node_modules/roboto-fontface-pre-css/css/roboto-fontface.less"],
service_worker: 'service_worker/service-worker.js'
};
function build_service_worker() {
console.info('Workbox libraries copying started.');
return workboxBuild.copyWorkboxLibraries(paths.public_view_dest).then((workboxDirectoryName) => {
console.info('Workbox libraries copied to: ' + workboxDirectoryName);
return workboxBuild.injectManifest({
swSrc: `${paths.service_worker}`,
swDest: `${paths.public_view_dest}/service-worker.js`,
maximumFileSizeToCacheInBytes: 50000000,
globDirectory: paths.public_view_dest,
globPatterns: ['**\/*.{html,js,css,png,svg,otf,ttf,eot,woff,woff2}'],
globIgnores: ['service-worker.js', 'manifest.json'].concat([`**/workbox*/*.js*`])
}).then((result) => {
result.warnings.forEach(console.warn);
console.info(`${result.count} files will be precached, totaling ${result.size} bytes.`);
console.info(`import ${paths.public_view_dest}${workboxDirectoryName}/workbox-sw.js to service-worker-script`);
gulp.src(`${paths.public_view_dest}/service-worker.js`)
.pipe(replace('#workbox-sw', `${workboxDirectoryName}/workbox-sw.js`))
.pipe(gulp.dest(paths.public_view_dest));
console.info('Service worker generation completed.');
});
}).catch((error) => {
console.warn('Workbox lbraries copying failed: ' + error);
});
}
// map error
function map_error(err) {
if (err.fileName) {
gutil.log(chalk.red(err.name)
+ ': '
+ chalk.yellow(err.fileName.replace(__dirname, ''))
+ ': '
+ 'Line '
+ chalk.magenta(err.lineNumber)
+ ' & '
+ 'Column '
+ chalk.magenta(err.columnNumber || err.column)
+ ': '
+ chalk.blue(err.description));
} else {
var message = err.message.replace(__dirname + "/", "");
gutil.log(chalk.red(err.name)
+ ': '
+ chalk.yellow(message));
}
this.emit('end');
}
function prevent_cache_assets(){
return function(){
return gulp.src(path.join(__dirname, paths.public_view_src + '*.html'))
.pipe(version_append(['html', 'js', 'css'],
{
appendType: 'timestamp',
versionFile: 'version.json'
}))
.pipe(gulp.dest(paths.public_view_dest));
};
}
function reactScript(watch) {
var bundler, rebundle;
bundler = browserify(paths.js.react[0], {
basedir: __dirname,
// debug: watch,
cache: {}, // required for watchify
packageCache: {}, // required for watchify
fullPaths: watch, // required to be true only for watchify
debug: argv.production ? false : true
});
if(watch) {
bundler = watchify(bundler);
}
bundler.transform('unreachable-branch-transform', {
global: true
});
bundler.transform(envify({
_: 'purge',
MODE: process.env.MODE
}));
bundler.transform(babelify.configure({
"plugins": ["object-assign"]
}));
rebundle = function() {
console.log("packing react");
var stream = bundler.bundle();
stream.on('error', map_error);
stream = stream.pipe(source('app.min.js'));
if(!watch) {
stream = stream.pipe(gulpif(argv.production, buffer()));
//stream = stream.pipe(uglifyJS());
}
return stream.pipe(gulp.dest('public/assets/dist'));
};
bundler.on('update', rebundle);
bundler.on('log', gutil.log);
return rebundle();
}
function es(){
return gulp.src('public/assets/dist/app.min.js')
.pipe(uglifyJS())
.pipe(gulp.dest('public/assets/dist'));
}
gulp.task('mini', es);
// task for stage or production
gulp.task('min', ['js', 'vendor', 'less', 'copyfonts', 'prevent_cache_assets']);
// init task
gulp.task('init', ['js', 'vendor', 'less', 'copyfonts', 'watch', 'prevent_cache_assets'], function () {
gulp.watch([paths.public_view_src + '**\/*', paths.service_worker, paths.public_view_dest + 'assets/**\/*.{html,js,css,png,svg,otf,ttf,eot,woff,woff2}'], ['build-service-worker']);
return build_service_worker();
});
// imagemin
gulp.task('clean-images-dest', function(){
return gulp.src('public/assets/img', {read: false})
.pipe(clean());
});
gulp.task('images', ['clean-images-dest'], function(){
return gulp.src(paths.images)
.pipe(imagemin())
.pipe(gulp.dest('public/assets/img'));
});
// react
gulp.task('react', function () {
return reactScript(false);
});
// copy fontawesome fonts task
gulp.task('copyfonts', function() {
return gulp.src(paths.fonts)
.on('error', map_error)
.pipe(gulp.dest('public/assets/css/fonts'));
});
// less task
gulp.task('less', ['images'], function(){
var l = less();
l.on('error', map_error);
return gulp.src(paths.less[0])
.pipe(l)
.pipe(postcss([prefixer({ browsers: ["> 0%"] })]))
.pipe(uglifyCSS())
.pipe(gulp.dest('public/assets/css'));
});
// copy lato fonts
gulp.task('cp-myriad-font', function(){
return gulp.src(['./node_modules/myriad-font/fonts/myriad/myriad-set-pro_text.woff', './node_modules/myriad-font/fonts/myriad/myriad-set-pro_bold.woff'])
.pipe(gulp.dest('public/assets/css/fonts'));
});
// vendor task
gulp.task('vendor', ['cp-myriad-font'], function(){
return gulp.src(paths.css)
.on('error', map_error)
.pipe(concat('vendor.css'))
.pipe(uglifyCSS())
.pipe(gulp.dest('public/assets/css/vendor'));
});
// prevent cache task
gulp.task('prevent_cache_assets', prevent_cache_assets());
// javascript task
gulp.task('js', ['js_vendor', 'js_plugins', 'js_register_service_worker'], function(){
return gulp.src(paths.js.app)
.on('error', map_error)
.pipe(concat('app.min.js'))
.pipe(uglifyJS())
.pipe(gulp.dest('public/assets/js'));
});
gulp.task('js_vendor', function(){
return gulp.src(paths.js.vendor)
.on('error', map_error)
.pipe(concat('vendor.min.js'))
.pipe(uglifyJS())
.pipe(gulp.dest('public/assets/js'));
});
gulp.task('js_plugins', function(){
return gulp.src(paths.js.plugins)
.on('error', map_error)
.pipe(concat('plugins.min.js'))
.pipe(uglifyJS())
.pipe(gulp.dest('public/assets/js'));
});
gulp.task('js_register_service_worker', function(){
return gulp.src(paths.js.register_service_worker)
.on('error', map_error)
.pipe(concat('register_service_worker.min.js'))
.pipe(uglifyJS())
.pipe(gulp.dest('public/assets/js'));
});
// task to run api
gulp.task('api', function(cb){
exec('cd ../mp-wallet-api && nodemon', function(err, stdout, stderr){
console.log(stdout);
console.log(stderr);
cb(err);
});
});
// watcher
gulp.task('watch', function(){
gulp.watch(paths.less, ['less']);
gulp.watch(paths.js.app, ['js']);
gulp.watch(paths.js.plugins, ['js']);
gulp.watch(paths.js.vendor, ['js']);
gulp.watch(paths.js.register_service_worker, ['js']);
gulp.watch(paths.css, ['vendor']);
gulp.watch(paths.fonts, ['copyfonts']);
gulp.watch(paths.public_view_src + '*.html', ['prevent_cache_assets']);
return reactScript(true);
});
gulp.task('connect', function() {
connect.server({
port: 3000,
root: [paths.public_view_dest],
middleware: function(connect, opt){
return [historyApiFallback({})];
},
fallback: 'index.html'
});
connect.serverClose();
});
gulp.task('set-production-env', function() {
return process.env.NODE_ENV = 'production';
});
gulp.task('default', ['set-production-env', 'init']);
gulp.task('serve', ['set-production-env', 'init', 'connect']);
gulp.task('with-api', ['set-production-env', 'api', 'init']);
gulp.task('build-service-worker', function () {
return build_service_worker();
});
My React project is only using gulp and browserify inside gulpfile.js, so this project doesn't use any build tools listed in documentation link below (grunt, webpack, browserify (standalone),rollup).
https://reactjs.org/docs/optimizing-performance.html
Do you have any suggestion how to eliminate dead code elimination, but only by using gulp and browserify inside it ? Thanks in advance.
I have simple test doing login and trying to check if it's success:
describe('My Angular App', function () {
describe('visiting the main homepage', function () {
beforeEach(function () {
browser.get('/');
element(By.id("siteLogin")).click();
});
it('should login successfully', function() {
element(By.name("login_username")).sendKeys("test#email.com");
element(By.name("login_password")).sendKeys("testpass");
element(By.id("formLoginButton")).click().then(function() {
browser.getCurrentUrl().then(function(url){
expect(url).toContain("profile");
});
});
});
});
});
It goes well until that last part where I'm checking URL, and in Selenium Server I get:
INFO - Executing: [execute async script: try { return (function (rootSelector, callback) {
var el = document.querySelector(rootSelector);
try {
if (window.getAngularTestability) {
window.getAngularTestability(el).whenStable(callback);
return;
}
if (!window.angular) {
throw new Error('angular could not be found on the window');
}
if (angular.getTestability) {
angular.getTestability(el).whenStable(callback);
} else {
if (!angular.element(el).injector()) {
throw new Error('root element (' + rootSelector + ') has no injector.' +
' this may mean it is not inside ng-app.');
}
angular.element(el).injector().get('$browser').
notifyWhenNoOutstandingRequests(callback);
}
} catch (err) {
callback(err.message);
}
}).apply(this, arguments); }
catch(e) { throw (e instanceof Error) ? e : new Error(e); }, [body]])
and also I get:
Failures:
1) My Angular App visiting the main homepage should login successfully
Message:
Error: Timeout - Async callback was not invoked within timeout specified by jasmine.DEFAULT_TIMEOUT_INTERVAL.
My protractor-conf.js:
exports.config = {
seleniumAddress: 'http://localhost:4444/wd/hub',
baseUrl: 'http://localhost:8080/Mysite',
capabilities: {
'browserName': 'firefox' // muste use firefox because I can't get .click() to work in Chrome
},
specs: [
'spec-e2e/*.js'
],
framework: 'jasmine2',
jasmineNodeOpts: {
isVerbose: true,
showColors: true,
defaultTimeoutInterval: 30000
}
};
I appreciate any help on this one.
Thanks
Looks like there is a non-Angular page opened after a click. If this is the case, you need to turn the synchronization between Protractor and Angular off:
afterEach(function () {
browser.ignoreSynchronization = false;
});
it('should login successfully', function() {
element(By.name("login_username")).sendKeys("test#email.com");
element(By.name("login_password")).sendKeys("testpass");
browser.ignoreSynchronization = true;
element(By.id("formLoginButton")).click().then(function() {
expect(browser.getCurrentUrl()).toContain("profile");
});
});
Note that you don't need to explicitly resolve the promise returned by getCurrentUrl and can let the expect() do that for you implicitly.
You may also need to wait for the URL to change:
var urlChanged = function(desiredUrl) {
return browser.getCurrentUrl().then(function(url) {
return url == desiredUrl;
});
};
browser.wait(urlChanged("my desired url"), 5000);
Every part of this is working except it's just dumping the initial junitresults.xml into the base folder and ignoring the code to put it into the reportPath folder.
The onComplete function is having no trouble accessing the global variables to use in its node_module. (I have to artificially have a test junitresults.xml file planted in the reportPath folder for it to work with though, because onPrepare isn't putting one there).
It seems like the function in onPrepare is totally ignoring the global variables set up inside the same onPrepare. How can I get it to access those? I even tried making a separate not-global variable for it to access and it is ignoring that too. Help please! Thanks!
...
multiCapabilities: [
{ browserName: 'firefox' },
{ browserName: 'chrome' }
],
onPrepare: function() {
var capsPromise = browser.getCapabilities();
capsPromise.then(function(caps) {
global.browserName = caps.caps_.browserName.replace(/ /g,"-");
global.browserVersion = caps.caps_.version;
// browserName = global.browserName; // was just testing if not-global would work
global.reportPath = 'c:/QA/test-results/' + global.browserName + '/';
});
var jasmineReporters = require('jasmine-reporters');
jasmine.getEnv().addReporter(new jasmineReporters.JUnitXmlReporter({
consolidateAll: true,
savePath: global.reportPath,
filePrefix: 'junitresults'
}));
return global.browserName, global.browserVersion, global.reportPath;
},
onComplete: function() {
var HTMLReport = require('jasmine-xml2html-converter');
// Call custom report for html output
testConfig = {
reportTitle: 'Test Execution Report',
outputPath: reportPath,
seleniumServer: 'default',
applicationUrl: browser.baseUrl,
testBrowser: global.browserName + ' v.' + global.browserVersion
};
new HTMLReport().from(reportPath + 'junitresults.xml', testConfig);
console.log("... aaaannnnd... done.");
},
Try putting the jasmine reporter initialization into getCapabilities promise resolution callback:
onPrepare: function() {
var capsPromise = browser.getCapabilities();
capsPromise.then(function(caps) {
var browserName = caps.caps_.browserName.replace(/ /g,"-");
var browserVersion = caps.caps_.version;
var reportPath = 'c:/QA/test-results/' + browserName + '/';
var jasmineReporters = require('jasmine-reporters');
jasmine.getEnv().addReporter(new jasmineReporters.JUnitXmlReporter({
consolidateAll: true,
savePath: reportPath,
filePrefix: 'junitresults'
}));
});
},
Also, instead of global, you may set properties on a globally available browser object.
This isn't making any reports happen at all. Can you see the reason why? Thanks!
onPrepare: function() {
var jasmineReporters = require('jasmine-reporters');
var capsPromise = browser.getCapabilities();
return capsPromise.then(function(caps){
var browserName = caps.caps_.browserName;
});
jasmine.getEnv().addReporter(new jasmineReporters.JUnitXmlReporter({
consolidateAll: false,
savePath: 'C:/QA/test_results/'
}));
},
// A callback function called once tests are finished.
onComplete: function() {
var path = require("path");
var browserName, browserVersion;
var reportPath = 'C:/QA/test_results/';
var capsPromise = browser.getCapabilities();
return capsPromise.then(function (caps) {
browserName = caps.caps_.browserName.toLowerCase();
browserName = browserName.replace(/ /g,"-");
browserVersion = caps.caps_.version;
return null;
});
var HTMLReport = require('jasmine-xml2html-converter');
reportPath += browserName;
// Call custom report for html output
testConfig = {
reportTitle: 'Test Execution Report',
outputPath: reportPath,
seleniumServer: browser.seleniumAddress,
applicationUrl: browser.baseUrl,
testBrowser: browserName + ' ' + browserVersion
};
new HTMLReport().from(reportPath + '/junitresults.xml', testConfig);
}
Your onPrepare function stops when reaching a "return" statement. Actually the addReporter function is never called.
You should add your jasmineReporter then storing your browser capabilities. Try something like this :
onPrepare: function() {
var jasmineReporters = require('jasmine-reporters');
jasmine.getEnv().addReporter(new jasmineReporters.JUnitXmlReporter({
consolidateAll: false,
savePath: 'C:/QA/test_results/'
}));
return browser.getCapabilities().then(function(caps){
var browserName = caps.caps_.browserName;
});
},
There is an change in the cap_method in latest selenium servers. Try something like this:
instead of:
return capsPromise.then(function (caps) {
browserName = caps.caps_.browserName.toLowerCase();
browserName = browserName.replace(/ /g,"-");
browserVersion = caps.caps_.version;
return null;
});
Use this:
browser.getCapabilities().then(function(c){
console.log(c.get('browserName'));
browserName = c.get('browserName').toLowerCase();
browserName = browserName.replace(/ /g,"-");
browserVersion = c.get('version');
return null;
});
I am able to generate html from xml however, testbrowser value in the html shows 'undefined'.
I have been trying to connect to MSSQL database using node module in my protractor tests. I tried both the methods below but each time I am either getting undefined is not a function or getting cannot read property of "query/execute".
Error: [launcher] Running 1 instances of WebDriver
[launcher] Error: TypeError: undefined is not a function
at exports.config.onPrepare (....\conf\Conf.js:39:28)
I have my connection defined in conf.js
var HtmlReporter = require('protractor-html-screenshot-reporter');
var mysql = require('../node_modules/mssql');
exports.config = {
seleniumAddress: 'http://localhost:4444/wd/hub', //desktop
allScriptsTimeout: 40000,
baseUrl: 'https://myurl.com/#/',
// frameworks to use
frameworks: 'jasmine',
//Capabilities to be passed to the webdriver instance.
multiCapabilities: [{
'browserName': 'chrome'
// }, {
// 'browserName': 'firefox'
//},
// {
// 'browserName': 'internet explorer'
}],
// Spec patterns are relative to the current working directory.
specs: [
'../tests/HomePage.js'
],
onPrepare: function() {
var sql = require('mssql/');
var config = {
server : '*****',
user : 'myusername',
password : 'pass',
database: 'mydb'
};
browser.driver.manage().window().maximize();
jasmine.getEnv().addReporter(new HtmlReporter({
baseDirectory: '/MyDirectory/screenshots'
}));
},
jasmineNodeOpts: {
showColors: true
}
};
In my Test, I did the following: test.js
describe ( " page test , function() {
it('Should add customer', function() {
blah blah....
});//This click will create a record in the backend
// I am attempting to get the record:
function runQuery() {
var connection = new sql.Connection(config, function(err) {
var request = new sql.Request(connection); // or: var request = connection.request();
request.query('select top 1 as result from customers', function(err, recordset) {
// ... error checks
console.log("this is the request: " + request);
console.dir(recordset);
});
});
};
I used dqlserver unofficial and it worked pretty well. We use Windows authentication to login to MSSQL studio so use the below.
var sql = require('node-sqlserver-unofficial');
var conn_str = "Driver={SQL Server Native Client 11.0};Server={your server};Database={your database};Trusted_Connection={Yes}";
sql.open(conn_str, function (err, conn) {
if (err) {
console.log("Error opening the connection!");
return;
}
conn.queryRaw("SELECT TOP 10 * FROM Employee", function (err, results) {
if (err) {
console.log("Error running query!");
return;
}
for (var i = 0; i < results.rows.length; i++) {
console.log("\n")
console.log("Record Info: ");
for (var j = 0; j < results.rows.length; j++) {
console.log(results.rows[i][j]);
}
}
});
});
Download MSSQL Unofficial package from here:
https://www.npmjs.com/package/node-sqlserver-unofficial