<commit_before>const ogs = require('../../index');

describe('basic', function () {
  it('using callbacks should return valid data', function () {
    return ogs({
      url: 'https://ogp.me/',
    }, function (error, result, response) {
      console.log('error:', error);
      console.log('result:', result);
      expect(error).to.be.eql(false);
      expect(result.ogTitle).to.be.eql('Open Graph protocol');
      expect(result.ogType).to.be.eql('website');
      expect(result.ogUrl).to.be.eql('https://ogp.me/');
      expect(result.ogDescription).to.be.eql('The Open Graph protocol enables any web page to become a rich object in a social graph.');
      expect(result.ogImage).to.be.eql({
        url: 'https://ogp.me/logo.png',
        width: '300',
        height: '300',
        type: 'image/png',
      });
      expect(result.requestUrl).to.be.eql('https://ogp.me/');
      expect(result.charset).to.be.eql('utf8');
      expect(result.success).to.be.eql(true);
      expect(result).to.have.all.keys('ogTitle', 'ogType', 'ogUrl', 'ogDescription', 'ogImage', 'requestUrl', 'charset', 'success');
      expect(response).to.be.an('object').and.to.not.be.empty;
    });
  });
  it('using promises should return valid data', function () {
    return ogs({ url: 'https://ogp.me/' })
      .then(function (data) {
        const { error, result, response } = data;
        console.log('error:', error);
        console.log('result:', result);
        expect(error).to.be.eql(false);
        expect(result.ogTitle).to.be.eql('Open Graph protocol');
        expect(result.ogType).to.be.eql('website');
        expect(result.ogUrl).to.be.eql('https://ogp.me/');
        expect(result.ogDescription).to.be.eql('The Open Graph protocol enables any web page to become a rich object in a social graph.');
        expect(result.ogImage).to.be.eql({
          url: 'https://ogp.me/logo.png',
          width: '300',
          height: '300',
          type: 'image/png',
        });
        expect(result.requestUrl).to.be.eql('https://ogp.me/');
        expect(result.charset).to.be.eql('utf8');
        expect(result.success).to.be.eql(true);
        expect(result).to.have.all.keys(
          'ogTitle',
          'ogType',
          'ogUrl',
          'ogDescription',
          'ogImage',
          'requestUrl',
          'charset',
          'success',
        );
        expect(response).to.be.an('object').and.to.not.be.empty;
      });
  });
  it('Test Name Cheap Page That Dose Not Have content-type=text/html - Should Return correct Open Graph Info', function () {
    return ogs({
      url: 'https://www.namecheap.com/',
    }, function (error, result, response) {
      console.log('error:', error);
      console.log('result:', result);
      expect(error).to.be.eql(false);
      expect(result.ogDescription).to.be.an('string').and.to.not.be.empty;
      expect(result.ogLocale).to.be.eql('en');
      expect(result.ogUrl).to.be.eql('https://www.namecheap.com/');
      expect(result.ogTitle).to.be.eql('Buy domain name - Cheap domain names from $1.37 - Namecheap');
      expect(result.ogDescription).to.be.eql('Namecheap offers cheap domain names with the most reliable service. Buy domain names with Namecheap and see why over 2 million customers trust us with over 10 million domains!');
      expect(result.ogImage).to.be.an('array').and.to.not.be.empty;
      expect(result.requestUrl).to.be.eql('https://www.namecheap.com/');
      expect(result.charset).to.be.eql('utf8');
      expect(result.success).to.be.eql(true);
      expect(result).to.have.all.keys(
        'ogTitle',
        'ogDescription',
        'ogImage',
        'ogLocale',
        'ogUrl',
        'requestUrl',
        'charset',
        'success',
      );
      expect(response).to.be.an('object').and.to.not.be.empty;
    });
  });
  it('vimeo.com should return open graph data', function () {
    return ogs({
      url: 'https://vimeo.com/232889838',
    }, function (error, result, response) {
      console.log('error:', error);
      console.log('result:', result);
      expect(error).to.be.eql(false);
      expect(result.alAndroidAppName).to.be.eql('Vimeo');
      expect(result.alAndroidPackage).to.be.eql('com.vimeo.android.videoapp');
      expect(result.alAndroidUrl).to.be.eql('vimeo://app.vimeo.com/videos/232889838');
      expect(result.alIosAppName).to.be.eql('Vimeo');
      expect(result.alIosAppStoreId).to.be.eql('425194759');
      expect(result.alIosUrl).to.be.eql('vimeo://app.vimeo.com/videos/232889838');
      expect(result.alWebShouldFallback).to.be.eql('true');
      expect(result.ogSiteName).to.be.eql('Vimeo');
      expect(result.ogUrl).to.be.eql('https://vimeo.com/232889838');
      expect(result.ogType).to.be.eql('video.other');
      expect(result.ogTitle).to.be.eql('Heroin');
      expect(result.ogDescription).to.be.an('string').and.to.not.be.empty;
      expect(result.twitterCard).to.be.eql('player');
      expect(result.twitterSite).to.be.eql('@vimeo');
      expect(result.twitterTitle).to.be.eql('Heroin');
      expect(result.twitterDescription).to.be.an('string').and.to.not.be.empty;
      expect(result.twitterAppNameiPhone).to.be.eql('Vimeo');
      expect(result.twitterAppIdiPhone).to.be.eql('425194759');
      expect(result.twitterAppUrliPhone).to.be.eql('vimeo://app.vimeo.com/videos/232889838');
      expect(result.twitterAppNameiPad).to.be.eql('Vimeo');
      expect(result.twitterAppIdiPad).to.be.eql('425194759');
      expect(result.twitterAppUrliPad).to.be.eql('vimeo://app.vimeo.com/videos/232889838');
      expect(result.twitterAppNameGooglePlay).to.be.eql('Vimeo');
      expect(result.twitterAppIdGooglePlay).to.be.eql('com.vimeo.android.videoapp');
      expect(result.twitterAppUrlGooglePlay).to.be.eql('vimeo://app.vimeo.com/videos/232889838');
      expect(result.ogLocale).to.be.eql('en');
      expect(result.ogImage).to.be.eql({
        url: 'https://i.vimeocdn.com/filter/overlay?src0=https%3A%2F%2Fi.vimeocdn.com%2Fvideo%2F659221704_1280x720.jpg&src1=https%3A%2F%2Ff.vimeocdn.com%2Fimages_v6%2Fshare%2Fplay_icon_overlay.png',
        width: '1280',
        height: '720',
        type: 'image/jpg',
      });
      expect(result.ogVideo).to.be.eql({
        url: 'https://player.vimeo.com/video/232889838?autoplay=1',
        width: '1280',
        height: '720',
        type: 'text/html',
      });
      expect(result.twitterImage).to.be.eql({
        url: 'https://i.vimeocdn.com/filter/overlay?src0=https%3A%2F%2Fi.vimeocdn.com%2Fvideo%2F659221704_1280x720.jpg&src1=https%3A%2F%2Ff.vimeocdn.com%2Fimages_v6%2Fshare%2Fplay_icon_overlay.png',
        width: null,
        height: null,
        alt: null,
      });
      expect(result.twitterPlayer).to.be.eql({
        url: 'https://player.vimeo.com/video/232889838',
        width: '1280',
        height: '720',
        stream: null,
      });
      expect(result.requestUrl).to.be.eql('https://vimeo.com/232889838');
      expect(result.charset).to.be.eql('utf8');
      expect(result.success).to.be.eql(true);
      expect(result).to.have.all.keys(
        'alAndroidAppName',
        'alAndroidPackage',
        'alAndroidUrl',
        'alIosAppName',
        'alIosAppStoreId',
        'alIosUrl',
        'alWebShouldFallback',
        'ogDescription',
        'ogImage',
        'ogLocale',
        'ogSiteName',
        'ogTitle',
        'ogType',
        'ogUrl',
        'ogVideo',
        'requestUrl',
        'success',
        'charset',
        'twitterAppIdGooglePlay',
        'twitterAppIdiPad',
        'twitterAppIdiPhone',
        'twitterAppNameGooglePlay',
        'twitterAppNameiPad',
        'twitterAppNameiPhone',
        'twitterAppUrlGooglePlay',
        'twitterAppUrliPad',
        'twitterAppUrliPhone',
        'twitterCard',
        'twitterDescription',
        'twitterImage',
        'twitterPlayer',
        'twitterSite',
        'twitterTitle',
      );
      expect(response).to.be.an('object').and.to.not.be.empty;
    });
  });
  it('mozilla.org should return open graph data with one title', function () {
    return ogs({
      url: 'https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toLocaleString',
    }, function (error, result, response) {
      console.log('error:', error);
      console.log('result:', result);
      expect(error).to.be.eql(false);
      expect(result.ogTitle).to.be.eql('Date.prototype.toLocaleString() - JavaScript | MDN');
      expect(result.ogDescription).to.be.eql('The toLocaleString() method returns a string with a\n' +'  language sensitive representation of this date.');
      expect(result.ogLocale).to.be.eql('en-US');
      expect(result.ogUrl).to.be.eql('https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toLocaleString');
      expect(result.ogDate).to.be.eql('2021-02-19T19:57:02.000Z');
      expect(result.charset).to.be.eql('utf8');
      expect(result.requestUrl).to.be.eql('https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toLocaleString');
      expect(result.success).to.be.eql(true);
      expect(result).to.have.all.keys(
        'charset',
        'ogDate',
        'ogDescription',
        'ogLocale',
        'ogTitle',
        'ogUrl',
        'requestUrl',
        'success',
      );
      expect(response).to.be.an('object').and.to.not.be.empty;
    });
  });
});
<commit_msg>fixing eslint issues<commit_after>const ogs = require('../../index');

describe('basic', function () {
  it('using callbacks should return valid data', function () {
    return ogs({
      url: 'https://ogp.me/',
    }, function (error, result, response) {
      console.log('error:', error);
      console.log('result:', result);
      expect(error).to.be.eql(false);
      expect(result.ogTitle).to.be.eql('Open Graph protocol');
      expect(result.ogType).to.be.eql('website');
      expect(result.ogUrl).to.be.eql('https://ogp.me/');
      expect(result.ogDescription).to.be.eql('The Open Graph protocol enables any web page to become a rich object in a social graph.');
      expect(result.ogImage).to.be.eql({
        url: 'https://ogp.me/logo.png',
        width: '300',
        height: '300',
        type: 'image/png',
      });
      expect(result.requestUrl).to.be.eql('https://ogp.me/');
      expect(result.charset).to.be.eql('utf8');
      expect(result.success).to.be.eql(true);
      expect(result).to.have.all.keys('ogTitle', 'ogType', 'ogUrl', 'ogDescription', 'ogImage', 'requestUrl', 'charset', 'success');
      expect(response).to.be.an('object').and.to.not.be.empty;
    });
  });
  it('using promises should return valid data', function () {
    return ogs({ url: 'https://ogp.me/' })
      .then(function (data) {
        const { error, result, response } = data;
        console.log('error:', error);
        console.log('result:', result);
        expect(error).to.be.eql(false);
        expect(result.ogTitle).to.be.eql('Open Graph protocol');
        expect(result.ogType).to.be.eql('website');
        expect(result.ogUrl).to.be.eql('https://ogp.me/');
        expect(result.ogDescription).to.be.eql('The Open Graph protocol enables any web page to become a rich object in a social graph.');
        expect(result.ogImage).to.be.eql({
          url: 'https://ogp.me/logo.png',
          width: '300',
          height: '300',
          type: 'image/png',
        });
        expect(result.requestUrl).to.be.eql('https://ogp.me/');
        expect(result.charset).to.be.eql('utf8');
        expect(result.success).to.be.eql(true);
        expect(result).to.have.all.keys(
          'ogTitle',
          'ogType',
          'ogUrl',
          'ogDescription',
          'ogImage',
          'requestUrl',
          'charset',
          'success',
        );
        expect(response).to.be.an('object').and.to.not.be.empty;
      });
  });
  it('Test Name Cheap Page That Dose Not Have content-type=text/html - Should Return correct Open Graph Info', function () {
    return ogs({
      url: 'https://www.namecheap.com/',
    }, function (error, result, response) {
      console.log('error:', error);
      console.log('result:', result);
      expect(error).to.be.eql(false);
      expect(result.ogDescription).to.be.an('string').and.to.not.be.empty;
      expect(result.ogLocale).to.be.eql('en');
      expect(result.ogUrl).to.be.eql('https://www.namecheap.com/');
      expect(result.ogTitle).to.be.eql('Buy domain name - Cheap domain names from $1.37 - Namecheap');
      expect(result.ogDescription).to.be.eql('Namecheap offers cheap domain names with the most reliable service. Buy domain names with Namecheap and see why over 2 million customers trust us with over 10 million domains!');
      expect(result.ogImage).to.be.an('array').and.to.not.be.empty;
      expect(result.requestUrl).to.be.eql('https://www.namecheap.com/');
      expect(result.charset).to.be.eql('utf8');
      expect(result.success).to.be.eql(true);
      expect(result).to.have.all.keys(
        'ogTitle',
        'ogDescription',
        'ogImage',
        'ogLocale',
        'ogUrl',
        'requestUrl',
        'charset',
        'success',
      );
      expect(response).to.be.an('object').and.to.not.be.empty;
    });
  });
  it('vimeo.com should return open graph data', function () {
    return ogs({
      url: 'https://vimeo.com/232889838',
    }, function (error, result, response) {
      console.log('error:', error);
      console.log('result:', result);
      expect(error).to.be.eql(false);
      expect(result.alAndroidAppName).to.be.eql('Vimeo');
      expect(result.alAndroidPackage).to.be.eql('com.vimeo.android.videoapp');
      expect(result.alAndroidUrl).to.be.eql('vimeo://app.vimeo.com/videos/232889838');
      expect(result.alIosAppName).to.be.eql('Vimeo');
      expect(result.alIosAppStoreId).to.be.eql('425194759');
      expect(result.alIosUrl).to.be.eql('vimeo://app.vimeo.com/videos/232889838');
      expect(result.alWebShouldFallback).to.be.eql('true');
      expect(result.ogSiteName).to.be.eql('Vimeo');
      expect(result.ogUrl).to.be.eql('https://vimeo.com/232889838');
      expect(result.ogType).to.be.eql('video.other');
      expect(result.ogTitle).to.be.eql('Heroin');
      expect(result.ogDescription).to.be.an('string').and.to.not.be.empty;
      expect(result.twitterCard).to.be.eql('player');
      expect(result.twitterSite).to.be.eql('@vimeo');
      expect(result.twitterTitle).to.be.eql('Heroin');
      expect(result.twitterDescription).to.be.an('string').and.to.not.be.empty;
      expect(result.twitterAppNameiPhone).to.be.eql('Vimeo');
      expect(result.twitterAppIdiPhone).to.be.eql('425194759');
      expect(result.twitterAppUrliPhone).to.be.eql('vimeo://app.vimeo.com/videos/232889838');
      expect(result.twitterAppNameiPad).to.be.eql('Vimeo');
      expect(result.twitterAppIdiPad).to.be.eql('425194759');
      expect(result.twitterAppUrliPad).to.be.eql('vimeo://app.vimeo.com/videos/232889838');
      expect(result.twitterAppNameGooglePlay).to.be.eql('Vimeo');
      expect(result.twitterAppIdGooglePlay).to.be.eql('com.vimeo.android.videoapp');
      expect(result.twitterAppUrlGooglePlay).to.be.eql('vimeo://app.vimeo.com/videos/232889838');
      expect(result.ogLocale).to.be.eql('en');
      expect(result.ogImage).to.be.eql({
        url: 'https://i.vimeocdn.com/filter/overlay?src0=https%3A%2F%2Fi.vimeocdn.com%2Fvideo%2F659221704_1280x720.jpg&src1=https%3A%2F%2Ff.vimeocdn.com%2Fimages_v6%2Fshare%2Fplay_icon_overlay.png',
        width: '1280',
        height: '720',
        type: 'image/jpg',
      });
      expect(result.ogVideo).to.be.eql({
        url: 'https://player.vimeo.com/video/232889838?autoplay=1',
        width: '1280',
        height: '720',
        type: 'text/html',
      });
      expect(result.twitterImage).to.be.eql({
        url: 'https://i.vimeocdn.com/filter/overlay?src0=https%3A%2F%2Fi.vimeocdn.com%2Fvideo%2F659221704_1280x720.jpg&src1=https%3A%2F%2Ff.vimeocdn.com%2Fimages_v6%2Fshare%2Fplay_icon_overlay.png',
        width: null,
        height: null,
        alt: null,
      });
      expect(result.twitterPlayer).to.be.eql({
        url: 'https://player.vimeo.com/video/232889838',
        width: '1280',
        height: '720',
        stream: null,
      });
      expect(result.requestUrl).to.be.eql('https://vimeo.com/232889838');
      expect(result.charset).to.be.eql('utf8');
      expect(result.success).to.be.eql(true);
      expect(result).to.have.all.keys(
        'alAndroidAppName',
        'alAndroidPackage',
        'alAndroidUrl',
        'alIosAppName',
        'alIosAppStoreId',
        'alIosUrl',
        'alWebShouldFallback',
        'ogDescription',
        'ogImage',
        'ogLocale',
        'ogSiteName',
        'ogTitle',
        'ogType',
        'ogUrl',
        'ogVideo',
        'requestUrl',
        'success',
        'charset',
        'twitterAppIdGooglePlay',
        'twitterAppIdiPad',
        'twitterAppIdiPhone',
        'twitterAppNameGooglePlay',
        'twitterAppNameiPad',
        'twitterAppNameiPhone',
        'twitterAppUrlGooglePlay',
        'twitterAppUrliPad',
        'twitterAppUrliPhone',
        'twitterCard',
        'twitterDescription',
        'twitterImage',
        'twitterPlayer',
        'twitterSite',
        'twitterTitle',
      );
      expect(response).to.be.an('object').and.to.not.be.empty;
    });
  });
  it('mozilla.org should return open graph data with one title', function () {
    return ogs({
      url: 'https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toLocaleString',
    }, function (error, result, response) {
      console.log('error:', error);
      console.log('result:', result);
      expect(error).to.be.eql(false);
      expect(result.ogTitle).to.be.eql('Date.prototype.toLocaleString() - JavaScript | MDN');
      expect(result.ogLocale).to.be.eql('en-US');
      expect(result.ogUrl).to.be.eql('https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toLocaleString');
      expect(result.ogDate).to.be.eql('2021-02-19T19:57:02.000Z');
      expect(result.charset).to.be.eql('utf8');
      expect(result.requestUrl).to.be.eql('https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toLocaleString');
      expect(result.success).to.be.eql(true);
      expect(result).to.have.all.keys(
        'charset',
        'ogDate',
        'ogDescription',
        'ogLocale',
        'ogTitle',
        'ogUrl',
        'requestUrl',
        'success',
      );
      expect(response).to.be.an('object').and.to.not.be.empty;
    });
  });
});
<|endoftext|>


<commit_before>'use strict';

let logger = require('../log.js');
let expressWinston = require('express-winston');
let addRequestId = require('express-request-id')();
let uuidV1 = require('uuid/v1');

let bodyParser = require('body-parser');
let cookieSession = require('cookie-session');
let express = require('express');
let path = require('path');

let passport = require('passport');
let OAuth2Strategy = require('passport-oauth2').Strategy;
let request = require('request');

let index = require('../routes/index');
let disclaimer = require('../routes/disclaimer');
let search = require('../routes/search');
let subject = require('../routes/subject');

let content = require('../data/content.js');

let config = require('../server/config');

//  Express Configuration
let app = express();

// Automatically log every request with user details, a unique session id, and a unique request id
app.use(addRequestId);
function requestLogger() {
    return expressWinston.logger({
        winstonInstance: logger,
        meta: true,
        dynamicMeta: function(req, res) {
            return {
                userId: req.user ? req.user.id : null,
                userEmail: req.user ? req.user.email : null,
                requestId: req.id,
                sessionTag: req.user ? req.user.sessionTag : null
            };
        },
        colorize: true,
        requestWhitelist: ['url', 'method', 'originalUrl', 'query', 'body']
    });
}

// SSO configuration
let testMode = process.env.NODE_ENV === 'test' ? 'true' : 'false';
let ssoConfig = config.sso;

app.use(cookieSession({
    name: 'session',
    keys: [Math.round(Math.random() * 100000).toString()],
    maxAge: 60 * 60 * 1000 // 60 minute
}));

if (testMode === 'true') {
    logger.info('Authentication disabled - using default test user profile');
    app.use(dummyUserProfile);
} else {
    logger.info('Authentication enabled');
    enableSSO();
}

// View Engine Configuration
app.set('views', path.join(__dirname, '..', 'views'));
app.set('view engine', 'jade');

// Server Configuration
app.set('port', process.env.PORT || 3000);

// Request Processing Configuration
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: false}));

//  Static Resources Configuration
app.use('/public', express.static(path.join(__dirname, '../public')));
app.use('/public', express.static(path.join(__dirname, '../govuk_modules/govuk_template/assets')));
app.use('/public', express.static(path.join(__dirname, '../govuk_modules/govuk_frontend_toolkit')));
app.use('/public/images/icons', express.static(path.join(__dirname, '../govuk_modules/govuk_frontend_toolkit/images')));

// GovUK Template Configuration
/* jshint ignore:start */
app.locals.asset_path = '/public/';
/* jshint ignore:end */

// Express Routing Configuration
app.use('/', index);
app.use('/disclaimer/', disclaimer);
if (testMode !== 'true') {
    app.use(authRequired);
    app.use(addTemplateVariables);
}
app.use(requestLogger());
app.use('/search/', search);
app.use('/subject/', subject);

// Error Handler
app.use(function(req, res, next) {
    let error = new Error('Not Found');
    error.status = 404;
    next(error);
});

app.use(logErrors);
app.use(clientErrors);

function logErrors(error, req, res, next) {
    logger.error('Unhandled error: ' + error.stack);
    next(error);
}

function clientErrors(error, req, res, next) {
    res.locals.message = error.message;
    res.locals.error = error;

    res.status(error.status || 500);

    res.render('error', {nav: true, content: content.view.error});
}

//  SSO utility methods
function authRequired(req, res, next) {
    if (!req.user) {
        logger.info('Authorisation required - redirecting to login');
        return res.redirect('/login');
    }
    if(!req.user.disclaimer) {
        logger.info('Disclaimer required - redirecting to disclaimer');
        return res.redirect('/disclaimer');
    }
    res.locals.nav = true;
    next();
}

function addTemplateVariables(req, res, next) {
    res.locals.profile = req.user;
    next();
}

function dummyUserProfile(req, res, next) {
    req.user = {
        'email': 'test@test.com',
        'firstName': 'Test',
        'lastName': 'Tester',
        'profileLink': '/profile',
        'logoutLink': '/logout'
    };
    res.locals.profile = req.user;
    next();
}

function enableSSO() {

    app.use(passport.initialize());
    app.use(passport.session());

    passport.use(new OAuth2Strategy({
            authorizationURL: ssoConfig.TOKEN_HOST + ssoConfig.AUTHORIZE_PATH,
            tokenURL: ssoConfig.TOKEN_HOST + ssoConfig.TOKEN_PATH,
            clientID: ssoConfig.CLIENT_ID,
            clientSecret: ssoConfig.CLIENT_SECRET
        },
        function(accessToken, refreshToken, profile, cb) {
            logger.info('Passport authentication invoked');

            let options = {
                uri: ssoConfig.TOKEN_HOST + ssoConfig.USER_DETAILS_PATH,
                qs: {access_token: accessToken},
                json: true
            };
            request(options, function(error, response, userDetails) {
                if (!error && response.statusCode === 200) {
                    logger.info('User authentication success');
                    return cb(null, userFor(userDetails));
                } else {
                    logger.error('Authentication failure:' + error);
                    return cb(error);
                }
            });
        })
    );

    function userFor(userDetails) {
        return {
            id: userDetails.id,
            email: userDetails.email,
            firstName: userDetails.first_name,
            lastName: userDetails.last_name,
            profileLink: userDetails.links.profile,
            logoutLink: userDetails.links.logout,
            sessionTag: uuidV1()
        };
    }

    passport.serializeUser(function(user, done) {
        // Not used but required for Passport
        done(null, user);
    });

    passport.deserializeUser(function(user, done) {
        // Not used but required for Passport
        done(null, user);
    });

}

module.exports = app;
<commit_msg>Tell OAuth to trust the upstream proxy<commit_after>'use strict';

let logger = require('../log.js');
let expressWinston = require('express-winston');
let addRequestId = require('express-request-id')();
let uuidV1 = require('uuid/v1');

let bodyParser = require('body-parser');
let cookieSession = require('cookie-session');
let express = require('express');
let path = require('path');

let passport = require('passport');
let OAuth2Strategy = require('passport-oauth2').Strategy;
let request = require('request');

let index = require('../routes/index');
let disclaimer = require('../routes/disclaimer');
let search = require('../routes/search');
let subject = require('../routes/subject');

let content = require('../data/content.js');

let config = require('../server/config');

//  Express Configuration
let app = express();

// Automatically log every request with user details, a unique session id, and a unique request id
app.use(addRequestId);
function requestLogger() {
    return expressWinston.logger({
        winstonInstance: logger,
        meta: true,
        dynamicMeta: function(req, res) {
            return {
                userId: req.user ? req.user.id : null,
                userEmail: req.user ? req.user.email : null,
                requestId: req.id,
                sessionTag: req.user ? req.user.sessionTag : null
            };
        },
        colorize: true,
        requestWhitelist: ['url', 'method', 'originalUrl', 'query', 'body']
    });
}

// SSO configuration
let testMode = process.env.NODE_ENV === 'test' ? 'true' : 'false';
let ssoConfig = config.sso;

app.use(cookieSession({
    name: 'session',
    keys: [Math.round(Math.random() * 100000).toString()],
    maxAge: 60 * 60 * 1000 // 60 minute
}));

if (testMode === 'true') {
    logger.info('Authentication disabled - using default test user profile');
    app.use(dummyUserProfile);
} else {
    logger.info('Authentication enabled');
    enableSSO();
}

// View Engine Configuration
app.set('views', path.join(__dirname, '..', 'views'));
app.set('view engine', 'jade');

// Server Configuration
app.set('port', process.env.PORT || 3000);

// Request Processing Configuration
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: false}));

//  Static Resources Configuration
app.use('/public', express.static(path.join(__dirname, '../public')));
app.use('/public', express.static(path.join(__dirname, '../govuk_modules/govuk_template/assets')));
app.use('/public', express.static(path.join(__dirname, '../govuk_modules/govuk_frontend_toolkit')));
app.use('/public/images/icons', express.static(path.join(__dirname, '../govuk_modules/govuk_frontend_toolkit/images')));

// GovUK Template Configuration
/* jshint ignore:start */
app.locals.asset_path = '/public/';
/* jshint ignore:end */

// Express Routing Configuration
app.use('/', index);
app.use('/disclaimer/', disclaimer);
if (testMode !== 'true') {
    app.use(authRequired);
    app.use(addTemplateVariables);
}
app.use(requestLogger());
app.use('/search/', search);
app.use('/subject/', subject);

// Error Handler
app.use(function(req, res, next) {
    let error = new Error('Not Found');
    error.status = 404;
    next(error);
});

app.use(logErrors);
app.use(clientErrors);

function logErrors(error, req, res, next) {
    logger.error('Unhandled error: ' + error.stack);
    next(error);
}

function clientErrors(error, req, res, next) {
    res.locals.message = error.message;
    res.locals.error = error;

    res.status(error.status || 500);

    res.render('error', {nav: true, content: content.view.error});
}

//  SSO utility methods
function authRequired(req, res, next) {
    if (!req.user) {
        logger.info('Authorisation required - redirecting to login');
        return res.redirect('/login');
    }
    if(!req.user.disclaimer) {
        logger.info('Disclaimer required - redirecting to disclaimer');
        return res.redirect('/disclaimer');
    }
    res.locals.nav = true;
    next();
}

function addTemplateVariables(req, res, next) {
    res.locals.profile = req.user;
    next();
}

function dummyUserProfile(req, res, next) {
    req.user = {
        'email': 'test@test.com',
        'firstName': 'Test',
        'lastName': 'Tester',
        'profileLink': '/profile',
        'logoutLink': '/logout'
    };
    res.locals.profile = req.user;
    next();
}

function enableSSO() {

    app.use(passport.initialize());
    app.use(passport.session());

    passport.use(new OAuth2Strategy({
            authorizationURL: ssoConfig.TOKEN_HOST + ssoConfig.AUTHORIZE_PATH,
            tokenURL: ssoConfig.TOKEN_HOST + ssoConfig.TOKEN_PATH,
            clientID: ssoConfig.CLIENT_ID,
            clientSecret: ssoConfig.CLIENT_SECRET,
            proxy: true // trust upstream proxy
        },
        function(accessToken, refreshToken, profile, cb) {
            logger.info('Passport authentication invoked');

            let options = {
                uri: ssoConfig.TOKEN_HOST + ssoConfig.USER_DETAILS_PATH,
                qs: {access_token: accessToken},
                json: true
            };
            request(options, function(error, response, userDetails) {
                if (!error && response.statusCode === 200) {
                    logger.info('User authentication success');
                    return cb(null, userFor(userDetails));
                } else {
                    logger.error('Authentication failure:' + error);
                    return cb(error);
                }
            });
        })
    );

    function userFor(userDetails) {
        return {
            id: userDetails.id,
            email: userDetails.email,
            firstName: userDetails.first_name,
            lastName: userDetails.last_name,
            profileLink: userDetails.links.profile,
            logoutLink: userDetails.links.logout,
            sessionTag: uuidV1()
        };
    }

    passport.serializeUser(function(user, done) {
        // Not used but required for Passport
        done(null, user);
    });

    passport.deserializeUser(function(user, done) {
        // Not used but required for Passport
        done(null, user);
    });

}

module.exports = app;
<|endoftext|>


<commit_before>const root = '../../';
const utils = require('../testing-utils.js');

beforeEach(function(){
  require(root + 'jspsych.js');
  require(root + 'plugins/jspsych-html-keyboard-response.js');
});

describe('loop function', function(){

  test('repeats a timeline when returns true', function(){

    var count = 0;

    var trial = {
      timeline: [{
        type: 'html-keyboard-response',
        stimulus: 'foo'
      }],
      loop_function: function(){
        if(count < 1){
          count++;
          return true;
        } else {
          return false;
        }
      }
    }

    jsPsych.init({
      timeline: [trial]
    });

    // first trial
    utils.pressKey(32);
    expect(jsPsych.data.get().count()).toBe(1);

    // second trial
    utils.pressKey(32);
    expect(jsPsych.data.get().count()).toBe(2);

  });

  test('does not repeat when returns false', function(){

    var count = 0;

    var trial = {
      timeline: [{
        type: 'html-keyboard-response',
        stimulus: 'foo'
      }],
      loop_function: function(){
        return false
      }
    }

    jsPsych.init({
      timeline: [trial]
    });

    // first trial
    utils.pressKey(32);

    expect(jsPsych.data.get().count()).toBe(1);

    // second trial
    utils.pressKey(32);

    expect(jsPsych.data.get().count()).toBe(1);

  });

  test('gets the data from the most recent iteration', function(){

    var data_count = [];
    var count = 0;

    var trial = {
      timeline: [{
        type: 'html-keyboard-response',
        stimulus: 'foo'
      }],
      loop_function: function(data){
        data_count.push(data.count());
        if(count < 2){
          count++;
          return true;
        } else {
          return false;
        }
      }
    }

    jsPsych.init({
      timeline: [trial]
    });

    // first trial
    utils.pressKey(32);

    // second trial
    utils.pressKey(32);

    // third trial
    utils.pressKey(32);

    expect(data_count).toEqual([1,1,1]);
    expect(jsPsych.data.get().count()).toBe(3);

  });

});

describe('conditional function', function(){

  test('skips the timeline when returns false', function(){

    var conditional = {
      timeline: [{
        type: 'html-keyboard-response',
        stimulus: 'foo'
      }],
      conditional_function: function(){
        return false;
      }
    }

    var trial = {
      type: 'html-keyboard-response',
      stimulus: 'bar'
    }

    jsPsych.init({
      timeline: [conditional, trial]
    });

    expect(jsPsych.getDisplayElement().innerHTML).toMatch('bar');

    // clear
    utils.pressKey(32);
  });

  test('completes the timeline when returns true', function(){
    var conditional = {
      timeline: [{
        type: 'html-keyboard-response',
        stimulus: 'foo'
      }],
      conditional_function: function(){
        return true;
      }
    }

    var trial = {
      type: 'html-keyboard-response',
      stimulus: 'bar'
    }

    jsPsych.init({
      timeline: [conditional, trial]
    });

    expect(jsPsych.getDisplayElement().innerHTML).toMatch('foo');

    // next
    utils.pressKey(32);

    expect(jsPsych.getDisplayElement().innerHTML).toMatch('bar');

    // clear
    utils.pressKey(32);
  });

  test('executes on every loop of the timeline', function(){

    var count = 0;
    var conditional_count = 0;

    var trial = {
      timeline: [{
        type: 'html-keyboard-response',
        stimulus: 'foo'
      }],
      loop_function: function(){
        if(count < 1){
          count++;
          return true;
        } else {
          return false;
        }
      },
      conditional_function: function(){
        conditional_count++;
        return true;
      }
    }

    jsPsych.init({
      timeline: [trial]
    });

    expect(conditional_count).toBe(1);

    // first trial
    utils.pressKey(32);

    expect(conditional_count).toBe(2);

    // second trial
    utils.pressKey(32);

    expect(conditional_count).toBe(2);
  });

});

describe('endCurrentTimeline', function(){

  test('stops the current timeline, skipping to the end after the trial completes', function(){
    var t = {
      timeline: [
        {
          type: 'html-keyboard-response',
          stimulus: 'foo',
          on_finish: function(){
            jsPsych.endCurrentTimeline();
          }
        },
        {
          type: 'html-keyboard-response',
          stimulus: 'bar'
        }
      ]
    }

    var t2 = {
      type: 'html-keyboard-response',
      stimulus: 'woo'
    }

    jsPsych.init({
      timeline: [t, t2]
    });

    expect(jsPsych.getDisplayElement().innerHTML).toMatch('foo');

    utils.pressKey(32);

    expect(jsPsych.getDisplayElement().innerHTML).toMatch('woo');

    utils.pressKey(32);

  });

});
<commit_msg>add test for nested timelines and endCurrentTimeline (#600)<commit_after>const root = '../../';
const utils = require('../testing-utils.js');

beforeEach(function(){
  require(root + 'jspsych.js');
  require(root + 'plugins/jspsych-html-keyboard-response.js');
});

describe('loop function', function(){

  test('repeats a timeline when returns true', function(){

    var count = 0;

    var trial = {
      timeline: [{
        type: 'html-keyboard-response',
        stimulus: 'foo'
      }],
      loop_function: function(){
        if(count < 1){
          count++;
          return true;
        } else {
          return false;
        }
      }
    }

    jsPsych.init({
      timeline: [trial]
    });

    // first trial
    utils.pressKey(32);
    expect(jsPsych.data.get().count()).toBe(1);

    // second trial
    utils.pressKey(32);
    expect(jsPsych.data.get().count()).toBe(2);

  });

  test('does not repeat when returns false', function(){

    var count = 0;

    var trial = {
      timeline: [{
        type: 'html-keyboard-response',
        stimulus: 'foo'
      }],
      loop_function: function(){
        return false
      }
    }

    jsPsych.init({
      timeline: [trial]
    });

    // first trial
    utils.pressKey(32);

    expect(jsPsych.data.get().count()).toBe(1);

    // second trial
    utils.pressKey(32);

    expect(jsPsych.data.get().count()).toBe(1);

  });

  test('gets the data from the most recent iteration', function(){

    var data_count = [];
    var count = 0;

    var trial = {
      timeline: [{
        type: 'html-keyboard-response',
        stimulus: 'foo'
      }],
      loop_function: function(data){
        data_count.push(data.count());
        if(count < 2){
          count++;
          return true;
        } else {
          return false;
        }
      }
    }

    jsPsych.init({
      timeline: [trial]
    });

    // first trial
    utils.pressKey(32);

    // second trial
    utils.pressKey(32);

    // third trial
    utils.pressKey(32);

    expect(data_count).toEqual([1,1,1]);
    expect(jsPsych.data.get().count()).toBe(3);

  });

});

describe('conditional function', function(){

  test('skips the timeline when returns false', function(){

    var conditional = {
      timeline: [{
        type: 'html-keyboard-response',
        stimulus: 'foo'
      }],
      conditional_function: function(){
        return false;
      }
    }

    var trial = {
      type: 'html-keyboard-response',
      stimulus: 'bar'
    }

    jsPsych.init({
      timeline: [conditional, trial]
    });

    expect(jsPsych.getDisplayElement().innerHTML).toMatch('bar');

    // clear
    utils.pressKey(32);
  });

  test('completes the timeline when returns true', function(){
    var conditional = {
      timeline: [{
        type: 'html-keyboard-response',
        stimulus: 'foo'
      }],
      conditional_function: function(){
        return true;
      }
    }

    var trial = {
      type: 'html-keyboard-response',
      stimulus: 'bar'
    }

    jsPsych.init({
      timeline: [conditional, trial]
    });

    expect(jsPsych.getDisplayElement().innerHTML).toMatch('foo');

    // next
    utils.pressKey(32);

    expect(jsPsych.getDisplayElement().innerHTML).toMatch('bar');

    // clear
    utils.pressKey(32);
  });

  test('executes on every loop of the timeline', function(){

    var count = 0;
    var conditional_count = 0;

    var trial = {
      timeline: [{
        type: 'html-keyboard-response',
        stimulus: 'foo'
      }],
      loop_function: function(){
        if(count < 1){
          count++;
          return true;
        } else {
          return false;
        }
      },
      conditional_function: function(){
        conditional_count++;
        return true;
      }
    }

    jsPsych.init({
      timeline: [trial]
    });

    expect(conditional_count).toBe(1);

    // first trial
    utils.pressKey(32);

    expect(conditional_count).toBe(2);

    // second trial
    utils.pressKey(32);

    expect(conditional_count).toBe(2);
  });

});

describe('endCurrentTimeline', function(){

  test('stops the current timeline, skipping to the end after the trial completes', function(){
    var t = {
      timeline: [
        {
          type: 'html-keyboard-response',
          stimulus: 'foo',
          on_finish: function(){
            jsPsych.endCurrentTimeline();
          }
        },
        {
          type: 'html-keyboard-response',
          stimulus: 'bar'
        }
      ]
    }

    var t2 = {
      type: 'html-keyboard-response',
      stimulus: 'woo'
    }

    jsPsych.init({
      timeline: [t, t2]
    });

    expect(jsPsych.getDisplayElement().innerHTML).toMatch('foo');

    utils.pressKey(32);

    expect(jsPsych.getDisplayElement().innerHTML).toMatch('woo');

    utils.pressKey(32);

  });

  test('works inside nested timelines', function(){
    var t = {
      timeline: [
        {
          timeline: [
            {
              type: 'html-keyboard-response',
              stimulus: 'foo',
              on_finish: function(){
                jsPsych.endCurrentTimeline();
              }
            },
            {
              type: 'html-keyboard-response',
              stimulus: 'skip me!'
            }
          ]
        },
        {
          type: 'html-keyboard-response',
          stimulus: 'bar'
        }
      ]
    }

    var t2 = {
      type: 'html-keyboard-response',
      stimulus: 'woo'
    }

    jsPsych.init({
      timeline: [t, t2]
    });

    expect(jsPsych.getDisplayElement().innerHTML).toMatch('foo');

    utils.pressKey(32);

    expect(jsPsych.getDisplayElement().innerHTML).toMatch('bar');

    utils.pressKey(32);

    expect(jsPsych.getDisplayElement().innerHTML).toMatch('woo');

    utils.pressKey(32);
  })

});
<|endoftext|>


<commit_before>var assert = require("assert")
, lessWatchCompilerUtils = require('../lib/lessWatchCompilerUtils.js')
, sh = require('shelljs')
, cwd = sh.pwd().toString();

// TODO - Add meaningful tests duh!

describe('lessWatchCompilerUtils Module API', function(){
  describe('Should have the following API\'s', function(){
    describe('walk()', function(){
        it('walk() function should be there', function(){
            assert.equal("function", typeof(lessWatchCompilerUtils.walk));
        });
        it('walk() function should return an object of files ', function(done){
            var timeout;
            lessWatchCompilerUtils.walk(cwd, {}, function(err, files){
                for (var i in files) {
                    assert.equal("object", typeof(files[i]));
                }
                //Hacky: walk() is calling back multiple times. This should be fixed.
                if (timeout) clearTimeout(timeout);
                timeout = setTimeout(function(){
                    done();
                },5)
            }, function(){});
        });
    })
     describe('watchTree()', function(){
        it('watchTree() function should be there', function(){
            assert.equal("function", typeof(lessWatchCompilerUtils.watchTree));
        });
        it('watchTree() function should complete and call a callback ', function(done){
            var timeout ;
            lessWatchCompilerUtils.watchTree(cwd, {}, function(){}, function(){
                if (timeout) clearTimeout(timeout);
                timeout = setTimeout(function(){
                    done();
                },2);
            });
        });
    })
    describe('compileCSS()', function(){
        it('compileCSS() function should be there', function(){
            assert.equal("function", typeof(lessWatchCompilerUtils.compileCSS));
        });
        it('should run the correct command with minified flag', function(){
            lessWatchCompilerUtils.config.outputFolder = "testFolder";
            lessWatchCompilerUtils.config.minified = true;
            assert.equal("lessc -x test testFolder/test.min.css", lessWatchCompilerUtils.compileCSS("test", true).command);
        });
        it('should run the correct command with sourceMap flag', function(){
            lessWatchCompilerUtils.config.outputFolder = "testFolder";
            lessWatchCompilerUtils.config.minified = false;
            lessWatchCompilerUtils.config.sourceMap = true;
            assert.equal("lessc --source-map test testFolder/test.css", lessWatchCompilerUtils.compileCSS("test", true).command);
        });
        it('should run the correct command with 1 plugin', function(){
            lessWatchCompilerUtils.config.outputFolder = "testFolder";
            lessWatchCompilerUtils.config.minified = false;
            lessWatchCompilerUtils.config.sourceMap = false;
            lessWatchCompilerUtils.config.plugins = "plugin1";
            assert.equal("lessc --plugin1 test testFolder/test.css", lessWatchCompilerUtils.compileCSS("test", true).command);
        });
        it('should run the correct command with 2 plugins', function(){
            lessWatchCompilerUtils.config.outputFolder = "testFolder";
            lessWatchCompilerUtils.config.minified = false;
            lessWatchCompilerUtils.config.sourceMap = false;
            lessWatchCompilerUtils.config.plugins = "plugin1,plugin2";
            assert.equal("lessc --plugin1 --plugin2 test testFolder/test.css", lessWatchCompilerUtils.compileCSS("test", true).command);
        });

        it('should run the correct command with minified flag', function(){
            lessWatchCompilerUtils.config.outputFolder = "testFolder";
            lessWatchCompilerUtils.config.minified = true;
            lessWatchCompilerUtils.config.sourceMap = false;
            lessWatchCompilerUtils.config.plugins = false;
            assert.equal("lessc -x test testFolder/test.min.css", lessWatchCompilerUtils.compileCSS("test", true).command);
        });
    })
    describe('filterFiles()', function(){
        it('filterFiles() function should be there', function(){
            assert.equal("function", typeof(lessWatchCompilerUtils.filterFiles));
        });
        lessWatchCompilerUtils.config.allowedExtensions = [".css"]
        it('filterFiles() function should return "false" for allowed files', function(){
            assert.equal(false, lessWatchCompilerUtils.filterFiles("file.css"));
        });
        it('filterFiles() function should return "true" for non-allowed files', function(){
            assert.equal(true, lessWatchCompilerUtils.filterFiles("file.js"));
        });

    })
    describe('getDateTime()', function(){
        it('getDateTime() function should be there and has value', function(){
            assert.equal(true, lessWatchCompilerUtils.getDateTime().length > 0);
        });
    })

  })
})
<commit_msg>test: Remove timeout from test<commit_after>var assert = require("assert")
, lessWatchCompilerUtils = require('../lib/lessWatchCompilerUtils.js')
, sh = require('shelljs')
, cwd = sh.pwd().toString();

// TODO - Add meaningful tests duh!

describe('lessWatchCompilerUtils Module API', function(){
  describe('Should have the following API\'s', function(){
    describe('walk()', function(){
        it('walk() function should be there', function(){
            assert.equal("function", typeof(lessWatchCompilerUtils.walk));
        });
        it('walk() function should return an object of files ', function(done){
            var timeout;
            lessWatchCompilerUtils.walk(cwd, {}, function(err, files){
                for (var i in files) {
                    assert.equal("object", typeof(files[i]));
                }
                done();
            }, function(){});
        });
    })
     describe('watchTree()', function(){
        it('watchTree() function should be there', function(){
            assert.equal("function", typeof(lessWatchCompilerUtils.watchTree));
        });
        it('watchTree() function should complete and call a callback ', function(done){
            var timeout ;
            lessWatchCompilerUtils.watchTree(cwd, {}, function(){}, function(){
                if (timeout) clearTimeout(timeout);
                timeout = setTimeout(function(){
                    done();
                },2);
            });
        });
    })
    describe('compileCSS()', function(){
        it('compileCSS() function should be there', function(){
            assert.equal("function", typeof(lessWatchCompilerUtils.compileCSS));
        });
        it('should run the correct command with minified flag', function(){
            lessWatchCompilerUtils.config.outputFolder = "testFolder";
            lessWatchCompilerUtils.config.minified = true;
            assert.equal("lessc -x test testFolder/test.min.css", lessWatchCompilerUtils.compileCSS("test", true).command);
        });
        it('should run the correct command with sourceMap flag', function(){
            lessWatchCompilerUtils.config.outputFolder = "testFolder";
            lessWatchCompilerUtils.config.minified = false;
            lessWatchCompilerUtils.config.sourceMap = true;
            assert.equal("lessc --source-map test testFolder/test.css", lessWatchCompilerUtils.compileCSS("test", true).command);
        });
        it('should run the correct command with 1 plugin', function(){
            lessWatchCompilerUtils.config.outputFolder = "testFolder";
            lessWatchCompilerUtils.config.minified = false;
            lessWatchCompilerUtils.config.sourceMap = false;
            lessWatchCompilerUtils.config.plugins = "plugin1";
            assert.equal("lessc --plugin1 test testFolder/test.css", lessWatchCompilerUtils.compileCSS("test", true).command);
        });
        it('should run the correct command with 2 plugins', function(){
            lessWatchCompilerUtils.config.outputFolder = "testFolder";
            lessWatchCompilerUtils.config.minified = false;
            lessWatchCompilerUtils.config.sourceMap = false;
            lessWatchCompilerUtils.config.plugins = "plugin1,plugin2";
            assert.equal("lessc --plugin1 --plugin2 test testFolder/test.css", lessWatchCompilerUtils.compileCSS("test", true).command);
        });

        it('should run the correct command with minified flag', function(){
            lessWatchCompilerUtils.config.outputFolder = "testFolder";
            lessWatchCompilerUtils.config.minified = true;
            lessWatchCompilerUtils.config.sourceMap = false;
            lessWatchCompilerUtils.config.plugins = false;
            assert.equal("lessc -x test testFolder/test.min.css", lessWatchCompilerUtils.compileCSS("test", true).command);
        });
    })
    describe('filterFiles()', function(){
        it('filterFiles() function should be there', function(){
            assert.equal("function", typeof(lessWatchCompilerUtils.filterFiles));
        });
        lessWatchCompilerUtils.config.allowedExtensions = [".css"]
        it('filterFiles() function should return "false" for allowed files', function(){
            assert.equal(false, lessWatchCompilerUtils.filterFiles("file.css"));
        });
        it('filterFiles() function should return "true" for non-allowed files', function(){
            assert.equal(true, lessWatchCompilerUtils.filterFiles("file.js"));
        });

    })
    describe('getDateTime()', function(){
        it('getDateTime() function should be there and has value', function(){
            assert.equal(true, lessWatchCompilerUtils.getDateTime().length > 0);
        });
    })

  })
})
<|endoftext|>


<commit_before>var chai   = require('chai'),
    helpers = require('./helpers.js'),
    expect = chai.expect,
    exec = require('child_process').exec,
    dom, child;

beforeEach(function(done){
  helpers.buildDom(function(window){
    dom = window;
    done();
  })
});

describe('Wiremock extension - mapping view controls', function(){

  it('should render a list of current mappings stored in wiremock', function(done){
    dom.$('#mappingControl').click();

    setTimeout(function(){
      var mappingRows = dom.$('.mapping .mappingTitle').map(function(){return dom.$(this).text();}).get();

      expect(mappingRows[0]).to.equal('   POST      /some/thing/else      400    ');
      expect(mappingRows[1]).to.equal('   GET      /some/thing      200    ');
      done();
    }, 1000);
  });

  it('should render JSON details for a mapping when clicking on a mapping entry', function(done){
    this.timeout(3000);

    dom.$('#mappingControl').click();

    setTimeout(function(){
      dom.$('.mappingTitle')[0].click();
      expect(dom.$('.mappingDetails:visible').length).to.equal(1);
      done();
    }, 1000);
  });

  it('should hide JSON details for a mapping when clicking twice on a mapping entry', function(done){
    this.timeout(3000);

    dom.$('#mappingControl').click();

    setTimeout(function(){
      dom.$('.mapping')[0].click();
      dom.$('.mapping')[0].click();

      expect(dom.$('.mappingDetails:visible').length).to.equal(0);
      done();
    }, 1000);
  });

  it('should delete a mapping when clicking on the delete button', function(done){
    this.timeout(3000);

    dom.$('#mappingControl').click();
    setTimeout(function(){
      dom.$('.deleteMapping')[0].click();
      setTimeout(function(){
        expect(dom.$('.mappingTitle').length).to.equal(2);
        done();
      }, 1000);
    }, 1000)
  });

  it('should move to edit stub view when selecting edit for a mapping', function(done){
    this.timeout(3000);

    dom.$('#mappingControl').click();

    setTimeout(function(){
      var idArray = dom.$('.mapping .deleteMapping').map(function(){return dom.$(this).attr('href');}).get();
      var id = idArray[1].split('/')[1];
      var editArray = dom.$('.mapping .editMapping').map(function(){return dom.$(this);}).get();
      editArray[1].click();

      setTimeout(function(){
        expect(dom.$('#stubView:visible').length).to.equal(1);

        // Request values
        expect(dom.$('#requestPath').val()).to.equal('/new/mapping');
        expect(dom.$('#requestType').val()).to.equal('PARTIAL');
        expect(dom.$('#requestMethod').val()).to.equal('PUT');
        expect(dom.$('#priority').val()).to.equal('2');

        // Query string matcher values
        var queryStringRows = dom.$('#form > .queryStringMatcher .key').map(function(){return dom.$(this).val();}).get();
        var queryStringMatchers = dom.$('#form > .queryStringMatcher .matcher').map(function(){return dom.$(this).val();}).get();
        var queryStringValues = dom.$('#form > .queryStringMatcher .value').map(function(){return dom.$(this).val();}).get();

        expect(queryStringRows[0]).to.equal('query1');
        expect(queryStringMatchers[0]).to.equal('equalTo');
        expect(queryStringValues[0]).to.equal('abc');
        expect(queryStringRows[1]).to.equal('query2');
        expect(queryStringMatchers[1]).to.equal('matches');
        expect(queryStringValues[1]).to.equal('def');
        expect(queryStringRows[2]).to.equal('query3');
        expect(queryStringMatchers[2]).to.equal('doesNotMatch');
        expect(queryStringValues[2]).to.equal('ghi');
        expect(queryStringRows[3]).to.equal('query4');
        expect(queryStringMatchers[3]).to.equal('contains');
        expect(queryStringValues[3]).to.equal('jkl');

        // Headers matcher values
        var headerStringRows = dom.$('#form > .requestHeader .key').map(function(){return dom.$(this).val();}).get();
        var headerStringMatchers = dom.$('#form > .requestHeader .matcher').map(function(){return dom.$(this).val();}).get();
        var headerStringValues = dom.$('#form > .requestHeader .value').map(function(){return dom.$(this).val();}).get();

        expect(headerStringRows[0]).to.equal('header1');
        expect(headerStringMatchers[0]).to.equal('equalTo');
        expect(headerStringValues[0]).to.equal('123');
        expect(headerStringRows[1]).to.equal('header2');
        expect(headerStringMatchers[1]).to.equal('matches');
        expect(headerStringValues[1]).to.equal('456');
        expect(headerStringRows[2]).to.equal('header3');
        expect(headerStringMatchers[2]).to.equal('doesNotMatch');
        expect(headerStringValues[2]).to.equal('789');
        expect(headerStringRows[3]).to.equal('header4');
        expect(headerStringMatchers[3]).to.equal('contains');
        expect(headerStringValues[3]).to.equal('135');

        // Request body matcher value
        expect(dom.$('#requestPayload').val()).to.equal('{\n \"body\":\"matcher\"\n}');

        // Response values
        expect(dom.$('#statusCode').val()).to.equal('200');

        // Response headers
        expect(dom.$('.responseHeader .key').val()).to.equal('responseheader1');
        expect(dom.$('.responseHeader .value').val()).to.equal('abc');

        expect(dom.$('#responsePayload').val()).to.equal('{\n \"response\":\"body\"\n}');

        expect(dom.$('#makeRequest').val()).to.equal('Update');
        expect(dom.$('#newForm').val()).to.equal('New stub');
        expect(dom.$('#editId').val()).to.equal(id);

        done();
      }, 1000);
    }, 1000);
  });

});
<commit_msg>Fixed broken test<commit_after>var chai   = require('chai'),
    helpers = require('./helpers.js'),
    expect = chai.expect,
    exec = require('child_process').exec,
    dom, child;

beforeEach(function(done){
  helpers.buildDom(function(window){
    dom = window;
    done();
  })
});

describe('Wiremock extension - mapping view controls', function(){

  it('should render a list of current mappings stored in wiremock', function(done){
    dom.$('#mappingControl').click();

    setTimeout(function(){
      var mappingRows = dom.$('.mapping .mappingTitle').map(function(){return dom.$(this).text();}).get();

      expect(mappingRows[0]).to.equal('   POST      /some/thing/else      400    ');
      expect(mappingRows[1]).to.equal('   GET      /some/thing      200    ');
      done();
    }, 1000);
  });

  it('should render JSON details for a mapping when clicking on a mapping entry', function(done){
    this.timeout(3000);

    dom.$('#mappingControl').click();

    setTimeout(function(){
      dom.$('.mappingTitle')[0].click();
      expect(dom.$('.mappingDetails:visible').length).to.equal(1);
      done();
    }, 1000);
  });

  it('should hide JSON details for a mapping when clicking twice on a mapping entry', function(done){
    this.timeout(3000);

    dom.$('#mappingControl').click();

    setTimeout(function(){
      dom.$('.mapping')[0].click();
      dom.$('.mapping')[0].click();

      expect(dom.$('.mappingDetails:visible').length).to.equal(0);
      done();
    }, 1000);
  });

  it('should delete a mapping when clicking on the delete button', function(done){
    this.timeout(3000);

    dom.$('#mappingControl').click();
    setTimeout(function(){
      dom.$('.deleteMapping')[0].click();
      setTimeout(function(){
        expect(dom.$('.mappingTitle').length).to.equal(2);
        done();
      }, 1000);
    }, 1000)
  });

  it('should move to edit stub view when selecting edit for a mapping', function(done){
    this.timeout(3000);

    dom.$('#mappingControl').click();

    setTimeout(function(){
      var idArray = dom.$('.mapping .deleteMapping').map(function(){return dom.$(this).attr('href');}).get();
      var id = idArray[1].split('/')[1];
      var editArray = dom.$('.mapping .editMapping').map(function(){return dom.$(this);}).get();
      editArray[1].click();

      setTimeout(function(){
        expect(dom.$('#stubView:visible').length).to.equal(1);

        // Request values
        expect(dom.$('#requestPath').val()).to.equal('/new/mapping');
        expect(dom.$('#requestType').val()).to.equal('PARTIAL');
        expect(dom.$('#requestMethod').val()).to.equal('PUT');
        expect(dom.$('#priority').val()).to.equal('2');

        // Query string matcher values
        var queryStringRows = dom.$('#form > .queryStringMatcher .key').map(function(){return dom.$(this).val();}).get();
        var queryStringMatchers = dom.$('#form > .queryStringMatcher .matcher').map(function(){return dom.$(this).val();}).get();
        var queryStringValues = dom.$('#form > .queryStringMatcher .value').map(function(){return dom.$(this).val();}).get();

        expect(queryStringRows[0]).to.equal('query1');
        expect(queryStringMatchers[0]).to.equal('equalTo');
        expect(queryStringValues[0]).to.equal('abc');
        expect(queryStringRows[1]).to.equal('query2');
        expect(queryStringMatchers[1]).to.equal('matches');
        expect(queryStringValues[1]).to.equal('def');
        expect(queryStringRows[2]).to.equal('query3');
        expect(queryStringMatchers[2]).to.equal('doesNotMatch');
        expect(queryStringValues[2]).to.equal('ghi');
        expect(queryStringRows[3]).to.equal('query4');
        expect(queryStringMatchers[3]).to.equal('contains');
        expect(queryStringValues[3]).to.equal('jkl');

        // Headers matcher values
        var headerStringRows = dom.$('#form > .requestHeader .key').map(function(){return dom.$(this).val();}).get();
        var headerStringMatchers = dom.$('#form > .requestHeader .matcher').map(function(){return dom.$(this).val();}).get();
        var headerStringValues = dom.$('#form > .requestHeader .value').map(function(){return dom.$(this).val();}).get();

        expect(headerStringRows[0]).to.equal('header1');
        expect(headerStringMatchers[0]).to.equal('equalTo');
        expect(headerStringValues[0]).to.equal('123');
        expect(headerStringRows[1]).to.equal('header2');
        expect(headerStringMatchers[1]).to.equal('matches');
        expect(headerStringValues[1]).to.equal('456');
        expect(headerStringRows[2]).to.equal('header3');
        expect(headerStringMatchers[2]).to.equal('doesNotMatch');
        expect(headerStringValues[2]).to.equal('789');
        expect(headerStringRows[3]).to.equal('header4');
        expect(headerStringMatchers[3]).to.equal('contains');
        expect(headerStringValues[3]).to.equal('135');

        // Request body matcher value
        expect(dom.$('#requestPayload').val()).to.equal('{\n \"body\":\"matcher\"\n}');

        // Response values
        expect(dom.$('#statusCode').val()).to.equal('200');

        // Response headers
        expect(dom.$('.responseHeader .key').val()).to.equal('responseheader1');
        expect(dom.$('.responseHeader .value').val()).to.equal('abc');

        expect(dom.$('#responsePayload').val()).to.equal('{\n \"response\":\"body\"\n}');

        expect(dom.$('#makeRequest').text()).to.equal('Update');
        expect(dom.$('#newForm').text()).to.equal('Create new stub');
        expect(dom.$('#editId').val()).to.equal(id);

        done();
      }, 1000);
    }, 1000);
  });

});
<|endoftext|>


<commit_before>const test = require('tape')
const nlp = require('../_lib')

test('named-match-or:', function(t) {
  let arr = [
    ['the dog played again', 'the [<target>(#Noun|#Verb)] played [<0>(#Adverb)]', 'dog'],
    ['the dog played again', 'the [<target>(#Noun|#Verb)] played [<another>(#Adverb)]', 'dog'],
    ['the dog played', 'the [<target>(#Noun|#Verb)] played', 'dog'],
    ['the dog played', 'the [<target>(#Noun)] played', 'dog'],
  ]

  arr.forEach(function(a) {
    const doc = nlp(a[0])
      .match(a[1])
      .byName('target')

    const msg = a[0] + ' matches ' + JSON.stringify(a[1]) + ' ' + a[2]
    t.equal(doc.text(), a[2], msg)
  })

  t.end()
})

test('named-match-auto:', function(t) {
  let arr = [
    ['the dog played', 'the [#Noun] played', 'dog'],
    ['the dog played', 'the [dog] played', 'dog'],
    ['the big dog played', 'the [big dog] played', 'big dog'],

    ['the dog played', 'the #Noun [played]', 'played'],
    ['the dog played', 'the dog [played]', 'played'],
    ['the big dog played', 'the big dog [played]', 'played'],
  ]

  arr.forEach(function(a) {
    const doc = nlp(a[0]).match(a[1])

    const res = doc.byName(0)

    const msg = a[0] + ' matches ' + JSON.stringify(a[1]) + ' ' + a[2]
    t.equal(res.text(), a[2], msg)
  })

  t.end()
})

test('named-match-auto-multi:', function(t) {
  let arr = [
    ['the dog played', 'the [#Noun] [played]', 'dog played'],
    ['the dog played lots', 'the [dog] played [<0>lots]', 'dog lots'],
    ['the big dog played', 'the [big dog] [played]', 'big dog played'],
  ]

  arr.forEach(function(a) {
    const doc = nlp(a[0]).match(a[1])

    const res = doc.byName(0)

    const msg = a[0] + ' matches ' + JSON.stringify(a[1]) + ' ' + a[2]
    t.equal(res.text(), a[2], msg)
  })

  t.end()
})

test('named-match-group', function(t) {
  const res = nlp('the dog played')
    .match('the [<type>#Noun] played')
    .byName()

  t.equal(res['type'].text(), 'dog')

  const doc2 = nlp('the big big big dog played').match('the [<size>#Adjective+] [<type>#Noun] played')
  const res2 = doc2.byName()

  t.equal(res2['type'].text(), 'dog')
  t.equal(res2['size'].text(), 'big big big')

  t.end()
})

test('named-match-to-json:', function(t) {
  let arr = [
    [
      'the dog played',
      'the [<target>#Noun] played',
      'dog',
      [{ text: 'dog', terms: [{ text: 'dog', tags: ['Noun', 'Singular'], pre: '', post: ' ' }] }],
    ],
    [
      'the dog played',
      'the [<target>dog] played',
      'dog',
      [{ text: 'dog', terms: [{ text: 'dog', tags: ['Noun', 'Singular'], pre: '', post: ' ' }] }],
    ],
    [
      'the big dog played',
      'the [<target>big dog] played',
      'big dog',
      [
        {
          text: 'big dog',
          terms: [
            { text: 'big', tags: ['Comparable', 'Adjective'], pre: '', post: ' ' },
            { text: 'dog', tags: ['Noun', 'Singular'], pre: '', post: ' ' },
          ],
        },
      ],
    ],
    [
      'the big dog played',
      'the [<target>big] dog [<target>played]',
      'big played',
      [
        { text: 'big', terms: [{ text: 'big', tags: ['Comparable', 'Adjective'], pre: '', post: ' ' }] },
        { text: 'played', terms: [{ text: 'played', tags: ['PastTense', 'Verb'], pre: '', post: '' }] },
      ],
    ],
  ]

  arr.forEach(function(a) {
    const doc = nlp(a[0]).match(a[1])

    const res = doc.byName()
    t.ok(res['target'], "Should contain 'target' group")

    const json = res.target.json()
    const text = res.target.text()

    t.equal(text, a[2])
    t.deepEqual(json, a[3], a[0])
  })

  t.end()
})

test('named-match-overlap', function(t) {
  const arr = [
    {
      input: 'the big dog played',
      match: 'the [<target>#Adjective] [<type>#Noun] [<target>played]',
      run: res => {
        t.equal(res['type'].text(), 'dog')
        t.equal(res['target'].text(), 'big played')
      },
    },
  ]

  arr.forEach(a =>
    a.run(
      nlp(a.input)
        .match(a.match)
        .byName()
    )
  )

  t.end()
})

test('named-object-match:', function(t) {
  let arr = [
    ['the dog played', [{ word: 'the' }, { tag: 'Noun', named: 'target' }, { word: 'played' }], 'dog'],
    ['the dog played', [{ word: 'dog', named: 'target' }], 'dog'],
    ['the dog played', [{ tag: 'Verb', named: 'target' }], 'played'],
  ]

  arr.forEach(function(a) {
    const doc = nlp(a[0])
      .match(a[1])
      .byName('target')

    const msg = a[0] + ' matches ' + JSON.stringify(a[1]) + ' ' + a[2]
    t.equal(doc.text(), a[2], msg)
  })

  t.end()
})

test('named-object-match-target:', function(t) {
  let arr = [
    ['the dog played', [{ word: 'the' }, { tag: 'Noun', named: 'target' }, { word: 'played' }], 'dog'],
    ['the dog played', [{ word: 'dog', named: 'target' }], 'dog'],
    ['the dog played', [{ tag: 'Verb', named: 'target' }], 'played'],

    ['the dog played', [{ word: 'the' }, { tag: 'Noun', named: 'not-target' }, { word: 'played' }], ''],
    ['the dog played', [{ word: 'dog', named: 'not-target' }], ''],
    ['the dog played', [{ tag: 'Verb', named: 'not-target' }], ''],
  ]

  arr.forEach(function(a) {
    const doc = nlp(a[0])
      .match(a[1])
      .byName('target')

    const msg = a[0] + ' matches ' + JSON.stringify(a[1]) + ' ' + a[2]
    t.equal(doc.text(), a[2], msg)
  })

  t.end()
})

test('named-object-match-number:', function(t) {
  let arr = [
    ['the dog played', [{ word: 'the' }, { tag: 'Noun', named: '0' }, { word: 'played' }], 'dog'],
    ['the dog played', [{ word: 'the' }, { tag: 'Noun', named: 0 }, { word: 'played' }], 'dog'],
    ['the dog played', [{ word: 'dog', named: 0 }], 'dog'],
    ['the dog played', [{ tag: 'Verb', named: 0 }], 'played'],

    ['the dog played', [{ word: 'the' }, { tag: 'Noun', named: 1 }, { word: 'played' }], ''],
    ['the dog played', [{ word: 'dog', named: 1 }], ''],
    ['the dog played', [{ tag: 'Verb', named: 1 }], ''],
  ]

  arr.forEach(function(a) {
    const doc = nlp(a[0])
      .match(a[1])
      .byName(0)

    const msg = a[0] + ' matches ' + JSON.stringify(a[1]) + ' ' + a[2]
    t.equal(doc.text(), a[2], msg)
  })

  t.end()
})

test('named-match:', function(t) {
  let arr = [
    ['the dog played', 'the [<target>#Noun] played', 'dog'],
    ['the dog played', 'the [<target>dog] played', 'dog'],
    ['the big dog played', 'the [<target>big dog] played', 'big dog'],
    ['the big dog played', 'the [<target>big dog] played', 'big dog'],
    ['the dog played', 'the dog [<target>#Verb]', 'played'],
  ]

  arr.forEach(function(a) {
    const doc = nlp(a[0])
      .match(a[1])
      .byName('target')

    const msg = a[0] + ' matches ' + JSON.stringify(a[1]) + ' ' + a[2]
    t.equal(doc.text(), a[2], msg)
  })

  t.end()
})

test('named-match-target:', function(t) {
  let arr = [
    ['the dog played', 'the [<target>#Noun] played', 'dog'],
    ['the dog played', 'the [<target>dog] played', 'dog'],
    ['the big dog played', 'the [<target>big dog] played', 'big dog'],

    ['the dog played', 'the [<not-target>#Noun] played', ''],
    ['the dog played', 'the [<not-target>dog] played', ''],
    ['the big dog played', 'the [<not-target>big dog] played', ''],
  ]

  arr.forEach(function(a) {
    const doc = nlp(a[0])
      .match(a[1])
      .byName('target')

    const msg = a[0] + ' matches ' + JSON.stringify(a[1]) + ' ' + a[2]
    t.equal(doc.text(), a[2], msg)
  })

  t.end()
})

test('named-match-number:', function(t) {
  let arr = [
    ['the dog played', 'the [<0>#Noun] played', 'dog'],
    ['the dog played', 'the [<0>dog] played', 'dog'],
    ['the big dog played', 'the [<0>big dog] played', 'big dog'],

    ['the dog played', 'the [<1>#Noun] played', ''],
    ['the dog played', 'the [<1>dog] played', ''],
    ['the big dog played', 'the [<1>big dog] played', ''],
  ]

  arr.forEach(function(a) {
    const doc = nlp(a[0])
      .match(a[1])
      .byName(0)

    const msg = a[0] + ' matches ' + JSON.stringify(a[1]) + ' ' + a[2]
    t.equal(doc.text(), a[2], msg)
  })

  t.end()
})

test('named-match-code-gen', function(t) {
  // Use group as arguments to function
  const group = nlp('the big dog played')
    .match('the [<size>#Adjective] [<type>#Noun] played')
    .byName()

  const codeFromGroup = ({ size, type }) => `size = '${size.text()}'; type = '${type.text()}'`
  t.equal(codeFromGroup(group), "size = 'big'; type = 'dog'", 'Should create code')

  // Convert group to sorted list and use as args
  const args = Object.keys(group)
    .sort((a, b) => a.localeCompare(b))
    .map(k => group[k])

  const codeFromList = (size, type) => `size = '${size.text()}'; type = '${type.text()}'`
  t.equal(codeFromList(...args), "size = 'big'; type = 'dog'", 'Should create code')

  /** Test fancy use of group by names */
  const templates = [
    {
      name: 'SetSize',
      match: '[<type>#Noun] size equals [<size>#Adjective]',
      fn: ({ size, type }) => `${type.text()}.size = ${size.text()}`,
    },
    {
      name: 'If',
      match: 'If [<a>#Verb] equals [<b>#Value] then [<contents>.+]',
      fn: ({ a, b, contents }) => `if(${a.text()} === ${b.text()}){${contents.text()}}`,
    },
  ]

  // Plugin for post processing matches and thunking the output
  const code = Doc => {
    Doc.prototype.toCode = function() {
      let output = ''

      for (let i = 0; i < templates.length; i++) {
        const template = templates[i]

        const res = this.if(template.match)
        if (res.found) {
          output += template.fn(res.byName())
        }
      }

      return output
    }
  }

  let output = nlp
    .clone()
    .extend(code)('if size equals 0 then do this, and this, and this')
    .toCode()
  t.equal(output, 'if(size === 0){do this, and this, and this}')

  // Use code generators
  output = nlp
    .clone()
    .extend(code)('Dog size equals big')
    .toCode()
  t.equal(output, 'Dog.size = big')

  t.end()
})
<commit_msg>Add test for overlap issue<commit_after>const test = require('tape')
const nlp = require('../_lib')

test('named-match-overlap', function(t) {
  let doc = nlp('june the 5th, july the 7th, and sept the 12th.')

  let m = doc.match('[<month>#Month]')

  t.equal(m.length, 3, 'Should have 3 results')

  t.equal(m.byName('month').length, 3, 'Should have 3 capture group results')

  t.end()
})

test('named-match-or:', function(t) {
  let arr = [
    ['the dog played again', 'the [<target>(#Noun|#Verb)] played [<0>(#Adverb)]', 'dog'],
    ['the dog played again', 'the [<target>(#Noun|#Verb)] played [<another>(#Adverb)]', 'dog'],
    ['the dog played', 'the [<target>(#Noun|#Verb)] played', 'dog'],
    ['the dog played', 'the [<target>(#Noun)] played', 'dog'],
  ]

  arr.forEach(function(a) {
    const doc = nlp(a[0])
      .match(a[1])
      .byName('target')

    const msg = a[0] + ' matches ' + JSON.stringify(a[1]) + ' ' + a[2]
    t.equal(doc.text(), a[2], msg)
  })

  t.end()
})

test('named-match-auto:', function(t) {
  let arr = [
    ['the dog played', 'the [#Noun] played', 'dog'],
    ['the dog played', 'the [dog] played', 'dog'],
    ['the big dog played', 'the [big dog] played', 'big dog'],

    ['the dog played', 'the #Noun [played]', 'played'],
    ['the dog played', 'the dog [played]', 'played'],
    ['the big dog played', 'the big dog [played]', 'played'],
  ]

  arr.forEach(function(a) {
    const doc = nlp(a[0]).match(a[1])

    const res = doc.byName(0)

    const msg = a[0] + ' matches ' + JSON.stringify(a[1]) + ' ' + a[2]
    t.equal(res.text(), a[2], msg)
  })

  t.end()
})

test('named-match-auto-multi:', function(t) {
  let arr = [
    ['the dog played', 'the [#Noun] [played]', 'dog played'],
    ['the dog played lots', 'the [dog] played [<0>lots]', 'dog lots'],
    ['the big dog played', 'the [big dog] [played]', 'big dog played'],
  ]

  arr.forEach(function(a) {
    const doc = nlp(a[0]).match(a[1])

    const res = doc.byName(0)

    const msg = a[0] + ' matches ' + JSON.stringify(a[1]) + ' ' + a[2]
    t.equal(res.text(), a[2], msg)
  })

  t.end()
})

test('named-match-group', function(t) {
  const res = nlp('the dog played')
    .match('the [<type>#Noun] played')
    .byName()

  t.equal(res['type'].text(), 'dog')

  const doc2 = nlp('the big big big dog played').match('the [<size>#Adjective+] [<type>#Noun] played')
  const res2 = doc2.byName()

  t.equal(res2['type'].text(), 'dog')
  t.equal(res2['size'].text(), 'big big big')

  t.end()
})

test('named-match-to-json:', function(t) {
  let arr = [
    [
      'the dog played',
      'the [<target>#Noun] played',
      'dog',
      [{ text: 'dog', terms: [{ text: 'dog', tags: ['Noun', 'Singular'], pre: '', post: ' ' }] }],
    ],
    [
      'the dog played',
      'the [<target>dog] played',
      'dog',
      [{ text: 'dog', terms: [{ text: 'dog', tags: ['Noun', 'Singular'], pre: '', post: ' ' }] }],
    ],
    [
      'the big dog played',
      'the [<target>big dog] played',
      'big dog',
      [
        {
          text: 'big dog',
          terms: [
            { text: 'big', tags: ['Comparable', 'Adjective'], pre: '', post: ' ' },
            { text: 'dog', tags: ['Noun', 'Singular'], pre: '', post: ' ' },
          ],
        },
      ],
    ],
    [
      'the big dog played',
      'the [<target>big] dog [<target>played]',
      'big played',
      [
        { text: 'big', terms: [{ text: 'big', tags: ['Comparable', 'Adjective'], pre: '', post: ' ' }] },
        { text: 'played', terms: [{ text: 'played', tags: ['PastTense', 'Verb'], pre: '', post: '' }] },
      ],
    ],
  ]

  arr.forEach(function(a) {
    const doc = nlp(a[0]).match(a[1])

    const res = doc.byName()
    t.ok(res['target'], "Should contain 'target' group")

    const json = res.target.json()
    const text = res.target.text()

    t.equal(text, a[2])
    t.deepEqual(json, a[3], a[0])
  })

  t.end()
})

test('named-match-overlap', function(t) {
  const arr = [
    {
      input: 'the big dog played',
      match: 'the [<target>#Adjective] [<type>#Noun] [<target>played]',
      run: res => {
        t.equal(res['type'].text(), 'dog')
        t.equal(res['target'].text(), 'big played')
      },
    },
  ]

  arr.forEach(a =>
    a.run(
      nlp(a.input)
        .match(a.match)
        .byName()
    )
  )

  t.end()
})

test('named-object-match:', function(t) {
  let arr = [
    ['the dog played', [{ word: 'the' }, { tag: 'Noun', named: 'target' }, { word: 'played' }], 'dog'],
    ['the dog played', [{ word: 'dog', named: 'target' }], 'dog'],
    ['the dog played', [{ tag: 'Verb', named: 'target' }], 'played'],
  ]

  arr.forEach(function(a) {
    const doc = nlp(a[0])
      .match(a[1])
      .byName('target')

    const msg = a[0] + ' matches ' + JSON.stringify(a[1]) + ' ' + a[2]
    t.equal(doc.text(), a[2], msg)
  })

  t.end()
})

test('named-object-match-target:', function(t) {
  let arr = [
    ['the dog played', [{ word: 'the' }, { tag: 'Noun', named: 'target' }, { word: 'played' }], 'dog'],
    ['the dog played', [{ word: 'dog', named: 'target' }], 'dog'],
    ['the dog played', [{ tag: 'Verb', named: 'target' }], 'played'],

    ['the dog played', [{ word: 'the' }, { tag: 'Noun', named: 'not-target' }, { word: 'played' }], ''],
    ['the dog played', [{ word: 'dog', named: 'not-target' }], ''],
    ['the dog played', [{ tag: 'Verb', named: 'not-target' }], ''],
  ]

  arr.forEach(function(a) {
    const doc = nlp(a[0])
      .match(a[1])
      .byName('target')

    const msg = a[0] + ' matches ' + JSON.stringify(a[1]) + ' ' + a[2]
    t.equal(doc.text(), a[2], msg)
  })

  t.end()
})

test('named-object-match-number:', function(t) {
  let arr = [
    ['the dog played', [{ word: 'the' }, { tag: 'Noun', named: '0' }, { word: 'played' }], 'dog'],
    ['the dog played', [{ word: 'the' }, { tag: 'Noun', named: 0 }, { word: 'played' }], 'dog'],
    ['the dog played', [{ word: 'dog', named: 0 }], 'dog'],
    ['the dog played', [{ tag: 'Verb', named: 0 }], 'played'],

    ['the dog played', [{ word: 'the' }, { tag: 'Noun', named: 1 }, { word: 'played' }], ''],
    ['the dog played', [{ word: 'dog', named: 1 }], ''],
    ['the dog played', [{ tag: 'Verb', named: 1 }], ''],
  ]

  arr.forEach(function(a) {
    const doc = nlp(a[0])
      .match(a[1])
      .byName(0)

    const msg = a[0] + ' matches ' + JSON.stringify(a[1]) + ' ' + a[2]
    t.equal(doc.text(), a[2], msg)
  })

  t.end()
})

test('named-match:', function(t) {
  let arr = [
    ['the dog played', 'the [<target>#Noun] played', 'dog'],
    ['the dog played', 'the [<target>dog] played', 'dog'],
    ['the big dog played', 'the [<target>big dog] played', 'big dog'],
    ['the big dog played', 'the [<target>big dog] played', 'big dog'],
    ['the dog played', 'the dog [<target>#Verb]', 'played'],
  ]

  arr.forEach(function(a) {
    const doc = nlp(a[0])
      .match(a[1])
      .byName('target')

    const msg = a[0] + ' matches ' + JSON.stringify(a[1]) + ' ' + a[2]
    t.equal(doc.text(), a[2], msg)
  })

  t.end()
})

test('named-match-target:', function(t) {
  let arr = [
    ['the dog played', 'the [<target>#Noun] played', 'dog'],
    ['the dog played', 'the [<target>dog] played', 'dog'],
    ['the big dog played', 'the [<target>big dog] played', 'big dog'],

    ['the dog played', 'the [<not-target>#Noun] played', ''],
    ['the dog played', 'the [<not-target>dog] played', ''],
    ['the big dog played', 'the [<not-target>big dog] played', ''],
  ]

  arr.forEach(function(a) {
    const doc = nlp(a[0])
      .match(a[1])
      .byName('target')

    const msg = a[0] + ' matches ' + JSON.stringify(a[1]) + ' ' + a[2]
    t.equal(doc.text(), a[2], msg)
  })

  t.end()
})

test('named-match-number:', function(t) {
  let arr = [
    ['the dog played', 'the [<0>#Noun] played', 'dog'],
    ['the dog played', 'the [<0>dog] played', 'dog'],
    ['the big dog played', 'the [<0>big dog] played', 'big dog'],

    ['the dog played', 'the [<1>#Noun] played', ''],
    ['the dog played', 'the [<1>dog] played', ''],
    ['the big dog played', 'the [<1>big dog] played', ''],
  ]

  arr.forEach(function(a) {
    const doc = nlp(a[0])
      .match(a[1])
      .byName(0)

    const msg = a[0] + ' matches ' + JSON.stringify(a[1]) + ' ' + a[2]
    t.equal(doc.text(), a[2], msg)
  })

  t.end()
})

test('named-match-code-gen', function(t) {
  // Use group as arguments to function
  const group = nlp('the big dog played')
    .match('the [<size>#Adjective] [<type>#Noun] played')
    .byName()

  const codeFromGroup = ({ size, type }) => `size = '${size.text()}'; type = '${type.text()}'`
  t.equal(codeFromGroup(group), "size = 'big'; type = 'dog'", 'Should create code')

  // Convert group to sorted list and use as args
  const args = Object.keys(group)
    .sort((a, b) => a.localeCompare(b))
    .map(k => group[k])

  const codeFromList = (size, type) => `size = '${size.text()}'; type = '${type.text()}'`
  t.equal(codeFromList(...args), "size = 'big'; type = 'dog'", 'Should create code')

  /** Test fancy use of group by names */
  const templates = [
    {
      name: 'SetSize',
      match: '[<type>#Noun] size equals [<size>#Adjective]',
      fn: ({ size, type }) => `${type.text()}.size = ${size.text()}`,
    },
    {
      name: 'If',
      match: 'If [<a>#Verb] equals [<b>#Value] then [<contents>.+]',
      fn: ({ a, b, contents }) => `if(${a.text()} === ${b.text()}){${contents.text()}}`,
    },
  ]

  // Plugin for post processing matches and thunking the output
  const code = Doc => {
    Doc.prototype.toCode = function() {
      let output = ''

      for (let i = 0; i < templates.length; i++) {
        const template = templates[i]

        const res = this.if(template.match)
        if (res.found) {
          output += template.fn(res.byName())
        }
      }

      return output
    }
  }

  let output = nlp
    .clone()
    .extend(code)('if size equals 0 then do this, and this, and this')
    .toCode()
  t.equal(output, 'if(size === 0){do this, and this, and this}')

  // Use code generators
  output = nlp
    .clone()
    .extend(code)('Dog size equals big')
    .toCode()
  t.equal(output, 'Dog.size = big')

  t.end()
})
<|endoftext|>


<commit_before>
var fs = require('fs');

var genConfigPath = 'capture/config.json'

var configJSON = fs.read(genConfigPath);
var config = JSON.parse(configJSON);
if (!config.paths) {
  config.paths = {};
}

var bitmaps_reference = config.paths.bitmaps_reference || 'bitmaps_reference';
var bitmaps_test = config.paths.bitmaps_test || 'bitmaps_test';
var compareConfigFileName = config.paths.compare_data || 'compare/config.json';
var viewports = config.viewports;
var scenarios = config.scenarios||config.grabConfigs;

var compareConfig = {testPairs:[]};

var casper = require("casper").create({
  // clientScripts: ["jquery.js"] //lets try not to use this it's 2014 already people...
});

casper.on('resource.received', function(resource) {
    //casper.echo(resource.url);
});

casper.on("page.error", function(msg, trace) {
  // this.echo("Remote Error >    " + msg, "error");
  // this.echo("file:     " + trace[0].file, "WARNING");
  // this.echo("line:     " + trace[0].line, "WARNING");
  // this.echo("function: " + trace[0]["function"], "WARNING");
});

casper.on('remote.message', function(message) {
  this.echo('remote console > ' + message);
});

casper.on('resource.received', function(resource) {
  var status = resource.status;
  if(status >= 400) {
    casper.log('remote error > ' + resource.url + ' failed to load (' + status + ')', 'error');
  }
});

function capturePageSelectors(url,scenarios,viewports,bitmaps_reference,bitmaps_test,isReference){

  var
    screenshotNow = new Date(),
    screenshotDateTime = screenshotNow.getFullYear() + pad(screenshotNow.getMonth() + 1) + pad(screenshotNow.getDate()) + '-' + pad(screenshotNow.getHours()) + pad(screenshotNow.getMinutes()) + pad(screenshotNow.getSeconds());

  var consoleBuffer = '';
  var scriptTimeout = 20000;

  casper.on('remote.message', function(message) {
      this.echo(message);
      consoleBuffer = consoleBuffer + '\n' + message;
  });

  casper.start();
  // casper.viewport(1280,1024);

  casper.each(scenarios,function(casper, scenario, scenario_index){

    if (scenario.cookiesJsonFile && fs.isFile(scenario.cookiesJsonFile)) {
      var cookiesJson = fs.read(scenario.cookiesJsonFile);
      var cookies = JSON.parse(cookiesJson);
      for (var i = 0; i < cookies.length; i++) {
        phantom.addCookie(cookies[i]);
      }
    }

    casper.each(viewports, function(casper, vp, viewport_index) {
      this.then(function() {
        this.viewport(vp.width||vp.viewport.width, vp.height||vp.viewport.height);
      });
      this.thenOpen(scenario.url, function() {

        casper.waitFor(
          function(){ //test
            if(!scenario.readyEvent)return true;
            var regExReadyFlag = new RegExp(scenario.readyEvent,'i');
            return consoleBuffer.search(regExReadyFlag)>=0;
          }
          ,function(){//on done
            consoleBuffer = '';
            casper.echo('Ready event received.');
          }
          ,function(){casper.echo('ERROR: casper timeout.')} //on timeout
          ,scriptTimeout
        );
        casper.wait(scenario.delay||1);

      });
      casper.then(function() {
        this.echo('Current location is ' + scenario.url, 'info');

        //var src = this.evaluate(function() {return document.body.outerHTML; });
        //this.echo(src);
      });

      this.then(function(){

        this.echo('Screenshots for ' + vp.name + ' (' + (vp.width||vp.viewport.width) + 'x' + (vp.height||vp.viewport.height) + ')', 'info');

        //HIDE SELECTORS WE WANT TO AVOID
            if ( scenario.hasOwnProperty('hideSelectors') ) {
              scenario.hideSelectors.forEach(function(o,i,a){
                casper.evaluate(function(o){
                  Array.prototype.forEach.call(document.querySelectorAll(o), function(s, j){
                    s.style.visibility='hidden';
                  });
                },o);
              });
            }

        //REMOVE UNWANTED SELECTORS FROM RENDER TREE
            if ( scenario.hasOwnProperty('removeSelectors') ) {
              scenario.removeSelectors.forEach(function(o,i,a){
                casper.evaluate(function(o){
                  Array.prototype.forEach.call(document.querySelectorAll(o), function(s, j){
                    s.style.display='none';
                  });
                },o);
              });
            }

        //CREATE SCREEN SHOTS AND TEST COMPARE CONFIGURATION (CONFIG FILE WILL BE SAVED WHEN THIS PROCESS RETURNS)
            // If no selectors are provided then set the default 'body'
            if ( !scenario.hasOwnProperty('selectors') ) {
              scenario.selectors = [ 'body' ];
            }
        scenario.selectors.forEach(function(o,i,a){
          var cleanedSelectorName = o.replace(/[^a-zA-Z\d]/,'');//remove anything that's not a letter or a number
          //var cleanedUrl = scenario.url.replace(/[^a-zA-Z\d]/,'');//remove anything that's not a letter or a number
          var fileName = scenario_index + '_' + i + '_' + cleanedSelectorName + '_' + viewport_index + '_' + vp.name + '.png';;

          var reference_FP  = bitmaps_reference + '/' + fileName;
          var test_FP       = bitmaps_test + '/' + screenshotDateTime + '/' + fileName;

          var filePath      = (isReference)?reference_FP:test_FP;

          casper.captureSelector(filePath, o);

          if (!isReference && fs.exists(filePath)) {
            compareConfig.testPairs.push({
              reference:reference_FP,
              test:test_FP,
              selector:o,
              fileName:fileName,
              label:scenario.label,
              misMatchThreshold: scenario.misMatchThreshold
            });
          }
          //casper.echo('remote capture to > '+filePath,'info');

        });//end topLevelModules.forEach

      });

    });//end casper.each viewports

  });//end casper.each scenario

}

//========================
//this query should be moved to the prior process
//`isReference` could be better passed as env parameter
var exists = fs.exists(bitmaps_reference);
var isReference = false;
if(!exists){isReference=true; console.log('CREATING NEW REFERENCE FILES')}
//========================

capturePageSelectors(
  'index.html'
  ,scenarios
  ,viewports
  ,bitmaps_reference
  ,bitmaps_test
  ,isReference
);

casper.run(function(){
  complete();
  this.exit();
});

function complete(){
  var configData = JSON.stringify(compareConfig,null,2);
  fs.touch(compareConfigFileName);
  fs.write(compareConfigFileName, configData, 'w');
  console.log(
    'Comparison config file updated.'
    //,configData
  );
}

function pad(number) {
  var r = String(number);
  if ( r.length === 1 ) {
    r = '0' + r;
  }
  return r;
}
<commit_msg>selectorNotFound case<commit_after>
var fs = require('fs');

var selectorNotFoundPath = 'capture/resources/selectorNotFound_noun_47569.png'
var genConfigPath = 'capture/config.json'

var configJSON = fs.read(genConfigPath);
var config = JSON.parse(configJSON);
if (!config.paths) {
  config.paths = {};
}

var bitmaps_reference = config.paths.bitmaps_reference || 'bitmaps_reference';
var bitmaps_test = config.paths.bitmaps_test || 'bitmaps_test';
var compareConfigFileName = config.paths.compare_data || 'compare/config.json';
var viewports = config.viewports;
var scenarios = config.scenarios||config.grabConfigs;

var compareConfig = {testPairs:[]};

var casper = require("casper").create({
  // clientScripts: ["jquery.js"] //lets try not to use this it's 2014 already people...
});

casper.on('resource.received', function(resource) {
    //casper.echo(resource.url);
});

casper.on("page.error", function(msg, trace) {
  // this.echo("Remote Error >    " + msg, "error");
  // this.echo("file:     " + trace[0].file, "WARNING");
  // this.echo("line:     " + trace[0].line, "WARNING");
  // this.echo("function: " + trace[0]["function"], "WARNING");
});

casper.on('remote.message', function(message) {
  this.echo('remote console > ' + message);
});

casper.on('resource.received', function(resource) {
  var status = resource.status;
  if(status >= 400) {
    casper.log('remote error > ' + resource.url + ' failed to load (' + status + ')', 'error');
  }
});

function capturePageSelectors(url,scenarios,viewports,bitmaps_reference,bitmaps_test,isReference){

  var
    screenshotNow = new Date(),
    screenshotDateTime = screenshotNow.getFullYear() + pad(screenshotNow.getMonth() + 1) + pad(screenshotNow.getDate()) + '-' + pad(screenshotNow.getHours()) + pad(screenshotNow.getMinutes()) + pad(screenshotNow.getSeconds());

  var consoleBuffer = '';
  var scriptTimeout = 20000;

  casper.on('remote.message', function(message) {
      this.echo(message);
      consoleBuffer = consoleBuffer + '\n' + message;
  });

  casper.start();
  // casper.viewport(1280,1024);

  casper.each(scenarios,function(casper, scenario, scenario_index){

    if (scenario.cookiesJsonFile && fs.isFile(scenario.cookiesJsonFile)) {
      var cookiesJson = fs.read(scenario.cookiesJsonFile);
      var cookies = JSON.parse(cookiesJson);
      for (var i = 0; i < cookies.length; i++) {
        phantom.addCookie(cookies[i]);
      }
    }

    casper.each(viewports, function(casper, vp, viewport_index) {
      this.then(function() {
        this.viewport(vp.width||vp.viewport.width, vp.height||vp.viewport.height);
      });
      this.thenOpen(scenario.url, function() {

        casper.waitFor(
          function(){ //test
            if(!scenario.readyEvent)return true;
            var regExReadyFlag = new RegExp(scenario.readyEvent,'i');
            return consoleBuffer.search(regExReadyFlag)>=0;
          }
          ,function(){//on done
            consoleBuffer = '';
            casper.echo('Ready event received.');
          }
          ,function(){casper.echo('ERROR: casper timeout.')} //on timeout
          ,scriptTimeout
        );
        casper.wait(scenario.delay||1);

      });
      casper.then(function() {
        this.echo('Current location is ' + scenario.url, 'info');

        //var src = this.evaluate(function() {return document.body.outerHTML; });
        //this.echo(src);
      });

      this.then(function(){

        this.echo('Screenshots for ' + vp.name + ' (' + (vp.width||vp.viewport.width) + 'x' + (vp.height||vp.viewport.height) + ')', 'info');

        //HIDE SELECTORS WE WANT TO AVOID
            if ( scenario.hasOwnProperty('hideSelectors') ) {
              scenario.hideSelectors.forEach(function(o,i,a){
                casper.evaluate(function(o){
                  Array.prototype.forEach.call(document.querySelectorAll(o), function(s, j){
                    s.style.visibility='hidden';
                  });
                },o);
              });
            }

        //REMOVE UNWANTED SELECTORS FROM RENDER TREE
            if ( scenario.hasOwnProperty('removeSelectors') ) {
              scenario.removeSelectors.forEach(function(o,i,a){
                casper.evaluate(function(o){
                  Array.prototype.forEach.call(document.querySelectorAll(o), function(s, j){
                    s.style.display='none';
                  });
                },o);
              });
            }

        //CREATE SCREEN SHOTS AND TEST COMPARE CONFIGURATION (CONFIG FILE WILL BE SAVED WHEN THIS PROCESS RETURNS)
            // If no selectors are provided then set the default 'body'
            if ( !scenario.hasOwnProperty('selectors') ) {
              scenario.selectors = [ 'body' ];
            }
        scenario.selectors.forEach(function(o,i,a){
          var cleanedSelectorName = o.replace(/[^a-zA-Z\d]/,'');//remove anything that's not a letter or a number
          //var cleanedUrl = scenario.url.replace(/[^a-zA-Z\d]/,'');//remove anything that's not a letter or a number
          var fileName = scenario_index + '_' + i + '_' + cleanedSelectorName + '_' + viewport_index + '_' + vp.name + '.png';;

          var reference_FP  = bitmaps_reference + '/' + fileName;
          var test_FP       = bitmaps_test + '/' + screenshotDateTime + '/' + fileName;

          var filePath      = (isReference)?reference_FP:test_FP;

          casper.captureSelector(filePath, o);

          if (fs.exists(filePath)) {
            fs.copy(selectorNotFoundPath, "testNotFoundFile.png");
          }

          if (!isReference) {
            compareConfig.testPairs.push({
              reference:reference_FP,
              test:test_FP,
              selector:o,
              fileName:fileName,
              label:scenario.label,
              misMatchThreshold: scenario.misMatchThreshold
            });
          }
          //casper.echo('remote capture to > '+filePath,'info');

        });//end topLevelModules.forEach

      });

    });//end casper.each viewports

  });//end casper.each scenario

}

//========================
//this query should be moved to the prior process
//`isReference` could be better passed as env parameter
var exists = fs.exists(bitmaps_reference);
var isReference = false;
if(!exists){isReference=true; console.log('CREATING NEW REFERENCE FILES')}
//========================

capturePageSelectors(
  'index.html'
  ,scenarios
  ,viewports
  ,bitmaps_reference
  ,bitmaps_test
  ,isReference
);

casper.run(function(){
  complete();
  this.exit();
});

function complete(){
  var configData = JSON.stringify(compareConfig,null,2);
  fs.touch(compareConfigFileName);
  fs.write(compareConfigFileName, configData, 'w');
  console.log(
    'Comparison config file updated.'
    //,configData
  );
}

function pad(number) {
  var r = String(number);
  if ( r.length === 1 ) {
    r = '0' + r;
  }
  return r;
}
<|endoftext|>