oss-specs/specs

View on GitHub
features-support/step_definitions/features.js

Summary

Maintainability
C
1 day
Test Coverage
'use strict';

var should = require('should');
var By = require('selenium-webdriver').By;
var until = require('selenium-webdriver').until;
var fs = require('fs-extra');
var r = require('request');
var tar = require('tar-fs');
var gunzip = require('gunzip-maybe');

const pageLoadTimeout = 30 * 1000;
const timeoutObject = {timeout: pageLoadTimeout};

// Deal with the non-standard webdriver promises.
function handleErr(cb) {
  return function(err) {
    return cb(err);
  };
}

/**
 * Given parameters on the world object, load a URL.
 * @param  {Function} callback Cucumber done callback OR a custom callback.
 * @return {undefined}
 * @this World
 */
function getProjectFromUrl(callback) {
  var world = this;
  var projectRetrievalUrl = 'http://localhost:' + world.appPort + '/?repo_url=' + encodeURIComponent(world.repoUrl);

  world.browser.get(projectRetrievalUrl)
    .then(world.browser.getPageSource.bind(world.browser), handleErr(callback))
    .then(function (body) {
      world.body = body;
      callback();
    }, handleErr(callback));
}

// The returned function is passed as a callback to getProjectFromUrl.
function getScenarioFromProject(callback, world) {
  return function(error) {
    if (error) {
      callback(error);
      return;
    }

    world.browser.findElements(By.css('.spec-link'))
      .then(function (specLinks) {
        var featureLink = specLinks[specLinks.length - 1];
        return world.browser.get(featureLink.getAttribute('href'));
      }, handleErr(callback))
      .then(world.browser.getPageSource.bind(world.browser), handleErr(callback))
      .then(function (body) {
        world.body = body;
        callback();
      }, handleErr(callback));
  };
}

module.exports = function () {

  this.Given(/^a URL representing a remote Git repo "([^"]*)"$/, function (repoUrl) {
    this.repoUrl = repoUrl;
  });


  this.When(/^an interested party wants to view the features in that repo\.?$/, timeoutObject, getProjectFromUrl);
  this.When(/^they request the features for the same repository again\.?$/, timeoutObject, getProjectFromUrl);
  this.When(/^an interested party wants to view the scenarios within a feature\.?$/, timeoutObject, function (callback) {
    var world = this;
    getProjectFromUrl.bind(world)(getScenarioFromProject(callback, world));
  });

  this.When(/^interested party wants to view HTML features in the repo$/, timeoutObject, function (callback) {
    this.browser.find(By.className('spec-link'))
        .then(function () {
          callback();
        });
  });

  function switchToDemoBranch(callback) {
    var world = this;
    var burgerMenuId = 'expand-collapse-repository-controls';
    var repositoryCongtrolsId = 'repository-controls';
    var projectShaElId = 'project-commit';
    var changeBranchSelectElId = 'change-branch-control';
    var testingBranchOptionValue = 'refs%2Fremotes%2Forigin%2Ftest%2FdoNotDelete';
    var burgerMenuEl;
    var repoControlsEl;


    // Get the burger menu element.
    world.browser.findElement(By.id(burgerMenuId))
      .then(function(_burgerMenuEl) {
        burgerMenuEl = _burgerMenuEl;
        return world.browser.findElement(By.id(repositoryCongtrolsId));

        // Get the repo controls element.
      })
      .then(function(_repoControlsEl) {
        repoControlsEl = _repoControlsEl;
        return repoControlsEl.getAttribute('class');

        // Open the repo controls.
      })
      .then(function(repoControlsClass) {
        var isClosed = repoControlsClass.indexOf('collapse') !== -1;
        if (isClosed) {
          return burgerMenuEl.click();
        }
        return;

        // Grab the current SHA
      })
      .then(function() {
        return world.browser.findElement(By.id(projectShaElId));
      })
      .then(function(_projectShaEl) {
        return _projectShaEl.getText();
      })
      .then(function(originalSha) {
        world.oringalSha = originalSha;

        // Grab the branch selecting control.
        return world.browser.findElement(By.id(changeBranchSelectElId));

        // Request to change branch.
      })
      .then(function(_changeBranchSelectEl) {
        return _changeBranchSelectEl.findElement(By.xpath('option[@value=\'' + testingBranchOptionValue + '\']'));
      })
      .then(function(_testBranchOptionEl) {
        world._testBranchOptionEl = _testBranchOptionEl;
        return _testBranchOptionEl.click();
      })
      .then(function () {
        // Waiting for the page to refresh after the click
        return world.browser.wait(until.stalenessOf(world._testBranchOptionEl));
      })
      .then(function () {
        callback();
      })
      .catch(function () {
        handleErr(callback);
      });
  }
  this.When(/^they decide to change which branch is being displayed$/, function (callback) {
    switchToDemoBranch.bind(this)(callback);
  });


  this.Then(/^the list of features will be visible\.?$/, function () {
    should.equal(
      /\.feature/i.test(this.body) && /\.md/i.test(this.body),
      true,
      'The returned document body does not contain the strings \'.feature\' and \'.md\'' + this.body);
  });

  this.Then(/^the scenarios will be visible\.?$/, function () {
    should.equal(/feature-title/i.test(this.body),
      true,
      'The returned document body does not contain a feature title');
  });

  // This has to wait for a page to load so it gets the page load time out.
  this.Then(/^the files from the selected branch are displayed\.$/, timeoutObject, function (callback) {
    var world = this;

    var projectShaElId = 'project-commit';

    // Get the new SHA.
    world.browser.findElement(By.id(projectShaElId))
      .then(function(_projectShaEl) {
        return _projectShaEl.getText();
      }, handleErr(callback))
      .then(function(newSha) {
        should.notEqual(newSha, world.oringalSha, 'The SHA did not change on changing branch.');
        callback();
      }, handleErr(callback));
  });

  this.When(/^the results are retrieved from a CI server\.?$/, timeoutObject, function (callback) {
    var world = this;

    var getResultsID='get-jenkins-results';
    var getResults;
    // get the get results button
    world.browser.findElement(By.id(getResultsID))
      .then(function(_getResults) {
        getResults = _getResults;
        return getResults.click();
      }, handleErr(callback))
      .then(world.browser.findElement(By.id(getResultsID)))
      .then(
        getProjectFromUrl.bind(world)(
        getScenarioFromProject(callback, world)
      )
    );
  });

  this.Then(/^the list of results for the feature will be visible\.$/, timeoutObject, function (callback) {
    var world = this;
    world.browser.findElement(By.css('.resultLink .PASSED'))
      .then(function(_resultButton) {
        return _resultButton.getAttribute('value');
      }, handleErr(callback))
      .then(function(resultValue) {
        should.equal(resultValue, 'PASSED', 'The value of the button was not PASSED, value was '+resultValue);
        callback();
      }, handleErr(callback));
  });

  this.When(/^an interested party wants to view the results for the features in that repo$/, timeoutObject, getProjectFromUrl);

  this.Then(/^the get results button is displayed\.$/, timeoutObject, function (callback) {
    var world = this;
    world.browser.findElement(By.css('.get-results')).then(function() {
      should.equal(true,true);
    }, function(err) {
      if (err.name && err.name === 'NoSuchElementError') {
        // should.equal(false,true,'element not displayed');
        should.fail('Could not find a get results button');
      } else {
        should.fail('Got the following unexpected error - ' + err);
      }
    });
    callback();
  });




  this.When(/^they decide to view HTML specification$/, function () {
    // Need to switch to a demo branch because we have HTML specification in there
    switchToDemoBranch.bind(this)();

    var world = this;
    return world.browser.findElement(By.css('.spec-link[href*=\\.html]'))
        .then(function (specLink) {
          // Navigates to a feature file
          return world.browser.get(specLink.getAttribute('href'));
        });
  });

  this.Then(/^HTML specification is displayed$/, function (callback) {
    var browser = this.browser;
    browser.findElement(By.css('section.html-body iframe'))
      .then(function (frame) {
        return browser.switchTo().frame(frame);
      })
      .then(function () {
        return browser.findElement(By.css('h1'));
      })
      .then(function (el) {
        return el.getText();
      })
      .then(function (h1Text) {
        should.equal(h1Text, 'Title');
        callback();
      })
      .catch(function () {
        handleErr(callback);
      });
  });

  this.Given(/^a user is viewing (.*) repository$/, function (repository, callback) {
    let archiveUrl = 'https://gist.github.com/sponte/1fa36cdb67ae2c8ac0fd70ed6e83b2d8/raw/26f767ac726e7eb6916813ba55e9f4b69517f787/specs.tar.gz';
    var world = this;
    world.repoUrl = 'https://github.com/oss-specs/specs';

    fs.mkdirs('project-data/projects', function () {
      var stream = r(archiveUrl)
          .pipe(gunzip())
          .pipe(tar.extract('project-data/projects/specs'));

      stream.on('finish', function () {
        world.browser.get('http://localhost:' + world.appPort + '/project/specs')
          .then(function() {
            callback();
          })
          .catch(function () {
            handleErr(callback);
          });
      });
    });
  });
};