grunt.initConfig in a callback does not work - deployment

I want to use grunt for deployment and therefore want to read in configuration of remote hosts based on the already existing ~/.ssh/config file.
To load that configuration I'm using sshconf but need to include the grunt.initConfig() call in the callback to have the configuration when defining environments.
var sshconf = require('sshconf');
module.exports = function(grunt) {
// Read in ssh configuration
sshconf.read(function(err, sshHosts) {
if (err)
console.log(err);
// SSH config loaded, now init grunt
grunt.initConfig({
sshconfig: {
staging: {
privateKey: grunt.file.read(sshHosts['project_staging'].properties.IdentityFile),
host: sshHosts['project_staging'].properties.HostName,
username: sshHosts['project_staging'].properties.User,
port: sshHosts['project_staging'].properties.Port || 22,
path: "/var/www/project"
},
production: {
// ...
}
},
// Tasks to be executed on remote server
sshexec: {
example_task: {
command: 'uptime && hostname'
}
},
sftp: {
deploy: {
files: {
"./": ["*.json", "*.js", "config/**", "controllers/**", "lib/**", "models/**", "public/**", "views/**"]
},
options: {
//srcBasePath: "test/",
createDirectories: true
}
}
}
// More tasks
// ...
});
grunt.loadNpmTasks('grunt-ssh');
// More plugins ...
});
};
When I call grunt --help it states:
> grunt --help
Grunt: The JavaScript Task Runner (v0.4.1)
…
Available tasks
(no tasks found)
If I do not wrap the grunt initiation in that callback (sshconf.read(function(err, sshHosts) {})) everything is working fine (except for the ssh config not loaded or not yet ready to be used).
Is what I am trying even possible and if so, how? Am I missing something obvious?

Grunt init cannot be used in an async fashion like this. Either read the sshconf synchronously, or use a task, as described in this answer: How can I perform an asynchronous operation before grunt.initConfig()?

Related

NextJS PWA Service worker map 404 in Production

I am trying to build a PWA with NextJS and this https://www.npmjs.com/package/next-pwa
It have been working fine in development, but know i try to build and run it in production.
It seems like the files below only is being build when i run it as dev and is thereby missing in the prod build.
enter image description here
Is this an error in my config?
module.exports = withImages(
withPWA({
pwa: {
dest: 'public'
},
env: {
apiUrl: process.env.API_URL
},
webpack: (config, { isServer }) => {
if (!isServer) {
config.node = {
fs: 'empty'
}
}
return config
}
})
)
Please help!

access browserify -r params in karma

I call browserify with npm from the package.json scripts block. Here's an abbreviated version of the script.
"build:js": "browserify -r ./config.js:config -e -d src/index.js > build/index.js"
Everything works great. Inside index.js, I just refer to this parameter using: require('config') and browserify does the rest.
Now I'm trying to set up karma with browserify for testing, and karma-browserify can't find that variable. I've looked around and haven't found much, but tried to add require: ['./src/app/config/config-dev.js'] to my karma.conf.js inside the browserify object, like so:
browserify: {
debug: true,
require: ['./src/app/config/config-dev.js']
}
But karma doesn't make the connection between the require statement in the index to the parameter file, if nothing else, then because it isn't named. What I need to know is the syntax for karma when I use browserify CLI to add a param.
Any pointers to documentation explaining this or ideas about what I could try here would be super helpful. Thanks!
Try adding your require resolution to your package.json under the "browser" field.
E.g.:
"browser": {
"config": "./config"
}
If you’re trying to have a different config based on your environment then you could do:
./config.js:
if (process.env.NODE_ENV === 'production') {
module.exports = { /* production config */ };
} else if (process.env.NODE_ENV === 'development') {
module.exports = { /* development config */ };
} else if (process.env.NODE_ENV === 'test') {
module.exports = { /* test config */ };
}
then in your package.json you would have something like:
"scripts": {
"build:js": "NODE_ENV=production browserify -d -e src/index.js",
"test": "NODE_ENV=test karma"
},
"browserify": {
"transform": [
"envify"
]
}
envify being a crucial part which allows you to replace environment variables with their string directly in the code. e.g.: process.env.NODE_ENV === 'development' might become simply 'development' === 'development'. Such things can then be removed with a minification tool like uglifyjs.

How to seed dev database in Sails.js in a reproducible way

I'm looking for a best way to seed my development database in sails js.
In rails I would just use the seeds.rb file but even without that I could use a rake task.
With sails I am unsure of how I could do this outside of manually doing it with sails console.
Please note that solutions which add logic to config/models and the models themselves for production seeding are not what I am looking for. I don't want these records to exist in production.
You can seed your database in the config/bootstrap.js file.
To seed it for a particular environment, what I usually do is:
// config/bootstrap.js
module.exports.bootstrap = function (cb) {
if(process.env.NODE_ENV !== 'development')
return cb();
// Do whatever you want
// And don't forget to...
return cb();
};
And to drop the database each time during the Sails lifting:
// config/env/development.js
module.exports = {
models: {
migrate: 'drop'
}
};
You can use test framework, like Mocha. At your development mode, switch your table name to development table. Here is step by step:
Install mocha with npm install mocha --save-dev
Create test/boostrap.test.js and fill with (configure as your needs), look at my configured connections, it'll override default connections at config.
var Sails = require('sails'),
sails;
before(function (done) {
Sails.lift({
log : {
level: 'error'
},
connections: {
mongodbServer: {
database: 'table_test'
}
},
models : {
migrate: 'drop'
}
}, function (err, server) {
sails = server;
done(err, sails);
});
});
after(function (done) {
// here you can clear fixtures, etc.
sails.lower(done);
});
Create another file for seeding your data, for example create test/inject/seed.js and fill with something like.
describe('data seeding', function(){
it('should seed data', function(done){
sails.models.someModel
.create({
name: 'Some Name'
})
.then(function(result){
done();
})
.catch(done);
});
});
Add this at your package.json under "scripts" key.
"test": "_mocha test/bootstrap.test.js test/inject/**/*.inject.js --no-timeouts"
Run it with npm test to seed your data.
If you need to use it at development mode, when you run sails lift, edit your config/env/development.js and add something like this.
module.exports = {
connections: {
mongodbServer: {
database: 'table_test'
}
}
};
Now your sails lift will use table_test instead of production table, so your production table will be clean.

How do I parameterize the baseUrl property of the protractor config file

I need to run my protractor tests in different contexts with different baseUrls in the config files. I don't want to use separate config files for each situation since that is more difficult to maintain. Rather, I want to pass the base url in as a command line parameter. Here is what I have tried so far:
The protractor.conf.js:
exports.config = {
onPrepare : {
...
exports.config.baseUrl = browser.params.baseUrl;
...
}
}
And to invoke protractor:
protractor protractor.conf.js --params.baseUrl 'http://some.server.com'
This does not work since it seems like the browser instance is already configured before onPrepare is called.
Similarly, I have tried this:
exports.config = {
baseUrl : browser.params.baseUrl
}
But this doesn't work either since it seems like the browser instance is not available when the config is being generated.
It looks like I can use standard node process.argv to access all command line arguments, but that seems to be going against the spirit of protractor.
What is the best way for me to do what I need to do?
Seems like this is already possible, but the documentation is spotty in this area. Looking at the code, however, protractor does support a number of seemingly undocumented command line arguments.
So, running something like this will work:
protractor --baseUrl='http://some.server.com' my.conf.js
The other option is to use gruntfile.js and have it call the protractor config file.
//gruntfile.js
module.exports = function (grunt) {
grunt.registerTask("default", "", function () {
});
//Configure main project settings
grunt.initConfig({
//Basic settings and infor about our plugins
pkg: grunt.file.readJSON('package.json'),
//Name of plugin
cssmin: {
},
protractor: {
options: {
configFile: "conf.js", // Default config file
keepAlive: true, // If false, the grunt process stops when the test fails.
noColor: false, // If true, protractor will not use colors in its output.
args: {
baseUrl: grunt.option('baseUrl') || 'http://localhost:6034/'
}
},
your_target: { // Grunt requires at least one target to run so you can simply put 'all: {}' here too.
options: {
configFile: "conf.js", // Target-specific config file
args: {
baseUrl: grunt.option('baseUrl') || 'http://localhost:63634/'
}
}
},
},
//uglify
uglify: {
}
});
//Load the plugin
grunt.loadNpmTasks('grunt-contrib-cssmin');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-protractor-runner');
//Do the Task
grunt.registerTask('default', ['cssmin']);
};
the Protractor config file: conf.js
exports.config = {
directConnect: true,
// Capabilities to be passed to the webdriver instance.
capabilities: {
'browserName': 'chrome',
'chromeOptions': {
args: ['--no-sandbox']
}
},
chromeOnly: true,
// Framework to use. Jasmine is recommended.
framework: 'jasmine',
// Spec patterns are relative to the current working directory when
// protractor is called.
specs: ['specs/*/*_spec.js'],
suites : {
abcIdentity : 'specs/abcIdentity/*_spec.js' //picks up all the _spec.js files
},
params: {
UserName: 'abc#test.com',
Password: '123'
},
// Options to be passed to Jasmine.
jasmineNodeOpts: {
defaultTimeoutInterval: 30000,
includeStackTrace: true
},
onPrepare: function () {
browser.driver.manage().window().maximize();
if (process.env.TEAMCITY_VERSION) {
var jasmineReporters = require('jasmine-reporters');
jasmine.getEnv().addReporter(new jasmineReporters.TeamCityReporter());
}
}
};
//To run with default url http://localhost:6034
grunt protractor
//To run with any other url
grunt protractor --baseUrl:"http://dev.abc.com/"
I know, old one. but if anyone is still looking for a way to define a url based on capability (I had to do this because Ionic 5 will run in browser on port 8100, but in the app - unchangable - without port declaration on port 80, I use Appium)
add a baseUrl parameter inside your capability declaration.
{
browserName: 'chrome',
baseUrl: 'http://localhost:8100' //not required but as example
}
{
...
app: 'path to app.apk',
baseUrl: 'http://localhost'
...
}
and then configure your onPrepare method as follows.
async onPrepare() {
const config = await browser.getProcessedConfig();
if(config.capabilities.hasOwnProperty('baseUrl')) {
browser.baseUrl = config.capabilities.baseUrl;
}
}
OnPrepare runs for each capability you define in your multiCapabilities array. the getProcessedConfig returns the config as you defined it, with the addition of the current capability. Since that method returns a promise, I use async/await for readability.
This way, you can have multiple capabilities running, with each different a different host.
Base url should be declared baseUrl: "", in config.ts
I am using cucumber hooks and the below code is added in hooks file to pass the required url based upon the environments
if(browser.params.baseUrl==="QA"){
console.log("Hello QA")
await browser.get("https://www.google.com");
} else {
console.log("Hi Dev")
await browser.get("https://www.gmail.com");
}
run the tests using protractor command
protractor --params.baseUrl 'QA' typeScript/config/config.js --cucumberOpts.tags="#CucumberScenario"

Using Grunt to Mock Endpoints

I'm using Yeoman, Grunt, and Bower, to construct a platform for building a frontend independently of a a backend. The idea would be that all of my (AngularJS) controller, services, factories, etc live in this project, and get injected afterwards into my serverside codebase based off the result of grunt build.
My question is:
How can I mock endpoints so that the Grunt server responds to the same endpoints as my (Rails) App will?
At the moment I am using:
angular.module('myApp', ['ngResource'])
.run(['$rootScope', function ($rootScope) {
$rootScope.testState = 'test';
}]);
And then in each of my individual services:
mockJSON = {'foo': 'myMockJSON'}
And on every method:
if($rootScope.testState == 'test'){
return mockJSON;
}
else {
real service logic with $q/$http goes here
}
Then after grunt build, testState = 'test' gets removed.
This is clearly a relatively janky architecture. How can I avoid it? How can I have Grunt respond to the same endpoints as my app (some of which have dynamic params) apply some logic (if necessary), and serve out a json file (possibly dependent on path params)?
I've fixed this issue by using express to write a server that responds with static json.
First I created a directory in my project called 'api'. Within that directory I have the following files:
package.json:
{
"name": "mockAPI",
"version": "0.0.0",
"dependencies": {
"express": "~3.3.4"
}
}
Then I run npm install in this directory.
index.js:
module.exports = require('./lib/server');
lib/server.js:
express = require('express');
var app = express();
app.get('/my/endpoint', function(req, res){
res.json({'foo': 'myMockJSON'});
});
module.exports = app
and finally in my global Gruntfile.js:
connect: {
options: {
port: 9000,
hostname: 'localhost',
},
livereload: {
options: {
middleware: function (connect, options) {
return [
lrSnippet,
mountFolder(connect, '.tmp'),
mountFolder(connect, yeomanConfig.app),
require('./api')
];
}
}
},
Then the services make the requests, and the express server serves the correct JSON.
After grunt build, the express server is simply replaced by a rails server.
As of grunt-contrib-connect v.0.7.0 you can also just add your custom middleware to the existing middleware stack without having to manually rebuild the existing middleware stack.
livereload: {
options: {
open: true,
base: [
'.tmp',
'<%= config.app %>'
],
middleware: function(connect, options, middlewares) {
// inject a custom middleware into the array of default middlewares
middlewares.push(function(req, res, next) {
if (req.url !== '/my/endpoint') {
return next();
}
res.writeHead(200, {'Content-Type': 'application/json' });
res.end("{'foo': 'myMockJSON'}");
});
return middlewares;
}
}
},
See https://github.com/gruntjs/grunt-contrib-connect#middleware for the official documentation.
Alternatively you can use the grunt-connect-proxy to proxy everything that is missing in your test server to an actual backend.
It's quite easy to install, just one thing to remember when adding proxy to your livereload connect middleware is to add it last, like this:
middleware: function (connect) {
return [
lrSnippet,
mountFolder(connect, '.tmp'),
mountFolder(connect, yeomanConfig.app),
proxySnippet
];
}
grunt-connect-prism is similar to the Ruby project VCR. It provides an easy way for front end developers to record HTTP responses returned by their API (or some other remote source) and replay them later. It's basically an HTTP cache, but for developers working on a Single Page Application (SPA). You can also generate stubs for API calls that don't exist, and populate them the way you want.
It's useful for mocking complex & high latency API calls during development. It's also useful when writing e2e tests for your SPA only, removing the server from the equation. This results in much faster execution of your e2e test suite.
Prism works by adding a custom connect middleware to the connect server provided by the grunt-contrib-connect plugin. While in 'record' mode it will generate a file per response on the filesystem with content like the following:
{
"requestUrl": "/api/ponies",
"contentType": "application/json",
"statusCode": 200,
"data": {
"text": "my little ponies"
}
}
DISCLAIMER: I'm the author of this project.
You can use Apache proxy and connect your REST server with gruntjs.
Apache would do this:
proxy / -> gruntjs
proxy /service -> REST server
you would use your application hitting Apache and angular.js application would think that is talking with itself so no cross domain problem.
Here is a great tutorial on how to set this up:
http://alfrescoblog.com/2014/06/14/angular-js-activiti-webapp-with-activiti-rest/
Just my alternative way that based on Abraham P's answer. It does not need to install express within 'api' folder. I can separate the mock services for certain files. For example, my 'api' folder contains 3 files:
api\
index.js // assign all the "modules" and then simply require that.
user.js // all mocking for user
product.js // all mocking for product
file user.js
var user = function(req, res, next) {
if (req.method === 'POST' && req.url.indexOf('/user') === 0) {
res.end(
JSON.stringify({
'id' : '5463c277-87c4-4f1d-8f95-7d895304de12',
'role' : 'admin'
})
);
}
else {
next();
}
}
module.exports = user;
file product.js
var product = function(req, res, next) {
if (req.method === 'POST' && req.url.indexOf('/product') === 0) {
res.end(
JSON.stringify({
'id' : '5463c277-87c4-4f1d-8f95-7d895304de12',
'name' : 'test',
'category': 'test'
})
);
}
else {
next();
}
}
module.exports = product;
index.js just assigns all the "modules" and we simply require that.
module.exports = {
product: require('./product.js'),
user: require('./user.js')
};
My Gruntfile.js file
connect: {
options: {
port: 9000,
// Change this to '0.0.0.0' to access the server from outside.
hostname: 'localhost',
livereload: 35729
},
livereload: {
options: {
open: true,
middleware: function (connect) {
return [
connect.static('.tmp'),
connect().use(
'/bower_components',
connect.static('./bower_components')
),
connect.static(appConfig.app),
require('./api').user,
require('./api').product,
];
}
}
}