diff --git a/README.md b/README.md index 52f854b6e..551e5f111 100644 --- a/README.md +++ b/README.md @@ -75,4 +75,4 @@ $ gulp e2e * [gulp.js](https://gulpjs.com/) * [jest](https://jestjs.io/) * [Jasmine](https://jasmine.github.io/) -* [Nightmare](http://www.nightmarejs.org/) +* [Puppeteer](https://pptr.dev/) diff --git a/db/docker.js b/db/docker.js new file mode 100644 index 000000000..d56f2ce10 --- /dev/null +++ b/db/docker.js @@ -0,0 +1,163 @@ +const exec = require('child_process').exec; +const log = require('fancy-log'); +const dataSources = require('../loopback/server/datasources.json'); + +module.exports = class Docker { + constructor(name) { + Object.assign(this, { + id: name, + name, + isRandom: name == null, + dbConf: Object.assign({}, dataSources.vn) + }); + } + + /** + * Builds the database image and runs a container. It only rebuilds the + * image when fixtures have been modified or when the day on which the + * image was built is different to today. Some workarounds have been used + * to avoid a bug with OverlayFS driver on MacOS. + */ + async run() { + let d = new Date(); + let pad = v => v < 10 ? '0' + v : v; + let stamp = `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}`; + await this.execP(`docker build --build-arg STAMP=${stamp} -t salix-db ./db`); + + let dockerArgs; + + if (this.isRandom) + dockerArgs = '-p 3306'; + else { + try { + await this.rm(); + } catch (e) {} + dockerArgs = `--name ${this.name} -p 3306:${this.dbConf.port}`; + } + + let runChown = process.platform != 'linux'; + + let container = await this.execP(`docker run --env RUN_CHOWN=${runChown} -d ${dockerArgs} salix-db`); + this.id = container.stdout; + + try { + if (this.isRandom) { + let inspect = await this.execP(`docker inspect -f "{{json .NetworkSettings}}" ${this.id}`); + let netSettings = JSON.parse(inspect.stdout); + + // this.dbConf.host = netSettings.Gateway; + this.dbConf.host = '127.0.0.1'; + this.dbConf.port = netSettings.Ports['3306/tcp'][0]['HostPort']; + } + + if (runChown) await this.wait(); + } catch (err) { + if (this.isRandom) + await this.rm(); + throw err; + } + } + + /** + * Does the minium effort to start the database container, if it doesn't exists + * calls the 'docker' task, if it is started does nothing. Keep in mind that when + * you do not rebuild the docker you may be using an outdated version of it. + * See the 'docker' task for more info. + */ + async start() { + let state; + try { + let result = await this.execP(`docker inspect -f "{{json .State}}" ${this.id}`); + state = JSON.parse(result.stdout); + } catch (err) { + return await this.run(); + } + + switch (state.Status) { + case 'running': + return; + case 'exited': + await this.execP(`docker start ${this.id}`); + await this.wait(); + return; + default: + throw new Error(`Unknown docker status: ${state.Status}`); + } + } + + wait() { + return new Promise((resolve, reject) => { + const mysql = require('mysql2'); + + let interval = 100; + let elapsedTime = 0; + let maxInterval = 4 * 60 * 1000; + + let myConf = { + user: this.dbConf.username, + password: this.dbConf.password, + host: this.dbConf.host, + port: this.dbConf.port + }; + + log('Waiting for MySQL init process...'); + + async function checker() { + elapsedTime += interval; + let state; + + try { + let result = await this.execP(`docker container inspect -f "{{json .State}}" ${this.id}`); + state = JSON.parse(result.stdout); + } catch (err) { + return reject(new Error(err.message)); + } + + if (state.Status === 'exited') + return reject(new Error('Docker exited, please see the docker logs for more info')); + + let conn = mysql.createConnection(myConf); + conn.on('error', () => {}); + conn.connect(err => { + conn.destroy(); + if (!err) { + log('MySQL process ready.'); + return resolve(); + } + + if (elapsedTime >= maxInterval) + reject(new Error(`MySQL not initialized whithin ${elapsedTime / 1000} secs`)); + else + setTimeout(bindedChecker, interval); + }); + } + let bindedChecker = checker.bind(this); + bindedChecker(); + }); + } + + rm() { + return this.execP(`docker rm -fv ${this.id}`); + } + + /** + * Promisified version of exec(). + * + * @param {String} command The exec command + * @return {Promise} The promise + */ + execP(command) { + return new Promise((resolve, reject) => { + exec(command, (err, stdout, stderr) => { + if (err) + reject(err); + else { + resolve({ + stdout: stdout, + stderr: stderr + }); + } + }); + }); + } +}; diff --git a/e2e/smokes-tests.js b/e2e/smokes-tests.js deleted file mode 100644 index 7b4e16edf..000000000 --- a/e2e/smokes-tests.js +++ /dev/null @@ -1,35 +0,0 @@ -require('babel-core/register')({presets: ['es2015']}); - -process.on('warning', warning => { - console.log(warning.name); - console.log(warning.message); - console.log(warning.stack); -}); - -let verbose = false; - -if (process.argv[2] === '--v') - verbose = true; - -let Jasmine = require('jasmine'); -let jasmine = new Jasmine(); -let SpecReporter = require('jasmine-spec-reporter').SpecReporter; - -jasmine.loadConfig({ - spec_files: [ - `${__dirname}/smokes/**/*[sS]pec.js`, - `${__dirname}/helpers/extensions.js` - ], - helpers: [] -}); - -jasmine.addReporter(new SpecReporter({ - spec: { - // displayStacktrace: 'summary', - displaySuccessful: verbose, - displayFailedSpec: true, - displaySpecDuration: true - } -})); - -jasmine.execute(); diff --git a/e2e/smokes/01_client_path.spec.js b/e2e/smokes/01_client_path.spec.js deleted file mode 100644 index 6c106b2eb..000000000 --- a/e2e/smokes/01_client_path.spec.js +++ /dev/null @@ -1,31 +0,0 @@ -import selectors from '../../helpers/selectors.js'; -import getBrowser from '../../helpers/puppeteer'; - -describe('create client path', () => { - let browser; - let page; - beforeAll(async() => { - browser = await getBrowser(); - page = browser.page; - await page.loginAndModule('employee', 'client'); - }); - - afterAll(async() => { - await browser.close(); - }); - - it('should access to the create client view by clicking the create-client floating button', async() => { - await page.waitToClick(selectors.clientsIndex.createClientButton); - let url = await page.expectURL('#!/client/create'); - - expect(url).toBe(true); - }); - - it('should cancel the client creation to go back to clients index', async() => { - await page.waitToClick(selectors.globalItems.applicationsMenuButton); - await page.waitToClick(selectors.globalItems.clientsButton); - let url = await page.expectURL('#!/client/index'); - - expect(url).toBe(true); - }); -}); diff --git a/gulpfile.js b/gulpfile.js index ff6c71aa4..b01c26752 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -1,11 +1,11 @@ require('require-yaml'); const gulp = require('gulp'); -const exec = require('child_process').exec; const PluginError = require('plugin-error'); const argv = require('minimist')(process.argv.slice(2)); const log = require('fancy-log'); const request = require('request'); const e2eConfig = require('./e2e/helpers/config.js'); +const Docker = require('./db/docker.js'); // Configuration @@ -18,10 +18,6 @@ let langs = ['es', 'en']; let srcDir = './front'; let modulesDir = './modules'; let buildDir = 'dist'; -let containerId = 'salix-db'; - -let dataSources = require('./loopback/server/datasources.json'); -let dbConf = dataSources.vn; let backSources = [ '!node_modules', @@ -63,7 +59,7 @@ function backWatch(done) { done: done }); } -backWatch.description = `Starts backend in waching mode`; +backWatch.description = `Starts backend in watcher mode`; const back = gulp.series(dockerStart, backWatch); back.description = `Starts backend and database service`; @@ -73,78 +69,64 @@ defaultTask.description = `Starts all application services`; // Backend tests -async function backTestOnce() { - let bootOptions; +async function backTestOnce(done) { + let err; + let dataSources = require('./loopback/server/datasources.json'); - if (argv['random']) - bootOptions = {dataSources}; + const container = new Docker(); + await container.run(); - let app = require(`./loopback/server/server`); - app.boot(bootOptions); + dataSources = JSON.parse(JSON.stringify(dataSources)); - await new Promise((resolve, reject) => { - const jasmine = require('gulp-jasmine'); - - let options = { - errorOnFail: false, - config: { - random: false - } - }; - - if (argv.junit) { - const reporters = require('jasmine-reporters'); - options.reporter = new reporters.JUnitXmlReporter(); - } - - let backSpecFiles = [ - 'back/**/*.spec.js', - 'loopback/**/*.spec.js', - 'modules/*/back/**/*.spec.js' - ]; - - gulp.src(backSpecFiles) - .pipe(jasmine(options)) - .on('end', resolve) - .on('error', reject) - .resume(); + Object.assign(dataSources.vn, { + host: container.dbConf.host, + port: container.dbConf.port }); + let bootOptions = {dataSources}; + + let app = require(`./loopback/server/server`); + + try { + app.boot(bootOptions); + + await new Promise((resolve, reject) => { + const jasmine = require('gulp-jasmine'); + + let options = { + errorOnFail: false, + config: { + random: false + } + }; + + if (argv.junit) { + const reporters = require('jasmine-reporters'); + options.reporter = new reporters.JUnitXmlReporter(); + } + + let backSpecFiles = [ + 'back/**/*.spec.js', + 'loopback/**/*.spec.js', + 'modules/*/back/**/*.spec.js' + ]; + + gulp.src(backSpecFiles) + .pipe(jasmine(options)) + .on('end', resolve) + .on('error', reject) + .resume(); + }); + } catch (e) { + err = e; + } await app.disconnect(); + await container.rm(); + done(); + if (err) + throw err; } -backTestOnce.description = `Runs the backend tests once, can receive --junit arg to save reports on a xml file`; - -async function backTestDockerOnce() { - let containerId = await docker(); - let err; - - try { - await backTestOnce(); - } catch (e) { - err = e; - } - - if (argv['random']) - await execP(`docker rm -fv ${containerId}`); - if (err) throw err; -} -backTestDockerOnce.description = `Runs backend tests using in site container once`; - -async function backTestDocker() { - let containerId = await docker(); - let err; - - try { - await backTest(); - } catch (e) { - err = e; - } - - if (argv['random']) - await execP(`docker rm -fv ${containerId}`); - if (err) throw err; -} -backTestDocker.description = `Runs backend tests restoring fixtures first`; +backTestOnce.description = `Runs the backend tests once using a random container, can receive --junit arg to save reports on a xml file`; function backTest(done) { const nodemon = require('gulp-nodemon'); @@ -210,6 +192,14 @@ function e2eSingleRun() { } e2eSingleRun.description = `Runs the e2e tests just once`; +e2e = gulp.series(docker, async function isBackendReady() { + const attempts = await backendStatus(); + log(`Backend ready after ${attempts} attempt(s)`); + + return attempts; +}, e2eSingleRun); +e2e.description = `Restarts database and runs the e2e tests`; + async function backendStatus() { const milliseconds = 250; return new Promise(resolve => { @@ -231,24 +221,6 @@ async function backendStatus() { } backendStatus.description = `Performs a simple requests to check the backend status`; -e2e = gulp.series(docker, async function isBackendReady() { - const attempts = await backendStatus(); - log(`Backend ready after ${attempts} attempt(s)`); - - return attempts; -}, e2eSingleRun); -e2e.description = `Restarts database and runs the e2e tests`; - -function smokesOnly() { - const jasmine = require('gulp-jasmine'); - return gulp.src('./e2e/smokes-tests.js') - .pipe(jasmine({reporter: 'none'})); -} -smokesOnly.description = `Runs the smokes tests only`; - -smokes = gulp.series(docker, smokesOnly); -smokes.description = `Restarts database and runs the smokes tests`; - function install() { const install = require('gulp-install'); const print = require('gulp-print'); @@ -414,156 +386,17 @@ function watch(done) { watch.description = `Watches for changes in routes and locale files`; // Docker - -/** - * Builds the database image and runs a container. It only rebuilds the - * image when fixtures have been modified or when the day on which the - * image was built is different to today. Some workarounds have been used - * to avoid a bug with OverlayFS driver on MacOS. - */ -async function docker() { - let d = new Date(); - let pad = v => v < 10 ? '0' + v : v; - let stamp = `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}`; - await execP(`docker build --build-arg STAMP=${stamp} -t salix-db ./db`); - - let dockerArgs = `--name ${containerId} -p 3306:${dbConf.port}`; - - if (argv['random']) - dockerArgs = '-p 3306'; - else { - try { - await execP(`docker rm -fv ${containerId}`); - } catch (e) {} - } - - let runChown = process.platform != 'linux'; - if (argv['run-chown']) runChown = true; - - let result = await execP(`docker run --env RUN_CHOWN=${runChown} -d ${dockerArgs} salix-db`); - containerId = result.stdout; - - try { - if (argv['random']) { - let inspect = await execP(`docker inspect -f "{{json .NetworkSettings}}" ${containerId}`); - let netSettings = JSON.parse(inspect.stdout); - - dbConf.host = netSettings.Gateway; - dbConf.port = netSettings.Ports['3306/tcp'][0]['HostPort']; - } - - if (runChown) await dockerWait(); - } catch (err) { - if (argv['random']) - await execP(`docker rm -fv ${containerId}`); - throw err; - } - - return containerId; -} -docker.description = `Builds the database image and runs a container`; - -/** - * Does the minium effort to start the database container, if it doesn't exists - * calls the 'docker' task, if it is started does nothing. Keep in mind that when - * you do not rebuild the docker you may be using an outdated version of it. - * See the 'docker' task for more info. - */ async function dockerStart() { - let state; - try { - let result = await execP(`docker inspect -f "{{json .State}}" ${containerId}`); - state = JSON.parse(result.stdout); - } catch (err) { - return await docker(); - } - - switch (state.Status) { - case 'running': - return; - case 'exited': - await execP(`docker start ${containerId}`); - await dockerWait(); - return; - default: - throw new Error(`Unknown docker status: ${state.Status}`); - } + const container = new Docker('salix-db'); + await container.start(); } -dockerStart.description = `Starts the database container`; +dockerStart.description = `Starts the salix-db container`; -function dockerWait() { - return new Promise((resolve, reject) => { - const mysql = require('mysql2'); - - let interval = 100; - let elapsedTime = 0; - let maxInterval = 4 * 60 * 1000; - - let myConf = { - user: dbConf.username, - password: dbConf.password, - host: dbConf.host, - port: dbConf.port - }; - - log('Waiting for MySQL init process...'); - checker(); - - async function checker() { - elapsedTime += interval; - let state; - - try { - let result = await execP(`docker container inspect -f "{{json .State}}" ${containerId}`); - state = JSON.parse(result.stdout); - } catch (err) { - return reject(new Error(err.message)); - } - - if (state.Status === 'exited') - return reject(new Error('Docker exited, please see the docker logs for more info')); - - let conn = mysql.createConnection(myConf); - conn.on('error', () => {}); - conn.connect(err => { - conn.destroy(); - if (!err) { - log('MySQL process ready.'); - return resolve(); - } - - if (elapsedTime >= maxInterval) - reject(new Error(`MySQL not initialized whithin ${elapsedTime / 1000} secs`)); - else - setTimeout(checker, interval); - }); - } - }); -} -dockerWait.description = `Waits until database service is ready`; - -// Helpers - -/** - * Promisified version of exec(). - * - * @param {String} command The exec command - * @return {Promise} The promise - */ -function execP(command) { - return new Promise((resolve, reject) => { - exec(command, (err, stdout, stderr) => { - if (err) - reject(err); - else { - resolve({ - stdout: stdout, - stderr: stderr - }); - } - }); - }); +async function docker() { + const container = new Docker('salix-db'); + await container.run(); } +docker.description = `Runs the salix-db container`; module.exports = { default: defaultTask, @@ -572,13 +405,8 @@ module.exports = { backOnly, backWatch, backTestOnce, - backTestDockerOnce, backTest, - backTestDocker, e2e, - e2eSingleRun, - smokes, - smokesOnly, i, install, build, @@ -590,7 +418,5 @@ module.exports = { localesRoutes, watch, docker, - dockerStart, - dockerWait, backendStatus, }; diff --git a/modules/zone/front/descriptor/index.js b/modules/zone/front/descriptor/index.js index 4b51c8011..288267bfe 100644 --- a/modules/zone/front/descriptor/index.js +++ b/modules/zone/front/descriptor/index.js @@ -19,7 +19,6 @@ class Controller extends Descriptor { const ticketsAmount = res.data.length; if (ticketsAmount) { const params = {ticketsAmount}; - console.log('ticketsAmount', res.data); const question = $t('This zone contains tickets', params, null, null, 'sanitizeParameters'); this.$.deleteZone.question = question; this.$.deleteZone.show();