daspec / daspec-js-npm

Console runner executing specs using Node.js
MIT License
3 stars 0 forks source link

using DaSpec with Protractor #1

Open philipbeadle opened 9 years ago

philipbeadle commented 9 years ago

Hey, loving DaSpec :) My question is how can I use it with Protractor? Ive tried making the main.js file a custom framework but Protractor doesn't like it.
DaSpec is exactly what Ive been looking for.

philipbeadle commented 9 years ago

Looks like i need to write something like this https://github.com/angular/protractor/blob/master/lib/frameworks/cucumber.js

gojko commented 9 years ago

@philipbeadle - unfortunately I have 0 experience with protractor, so I can't help much with this, but if you want to give it a shot to write a framework integration into protractor, that would be fantastic

philipbeadle commented 9 years ago

I'm working on it right now :) I'll get onto Sam who wrote the Meteor Cucumber package and see if he can get DaSpec working too. Thanx for this its just what i was working on.

philipbeadle commented 9 years ago

Here it is. First shot at an adapter for DaSpec.

var util = require('util'),
    q = require('q'),
    log = require('../logger');
var testResult = [],
    failedCount = 0;
/**
 * A debug framework which does not actually run any tests, just spits
 * out the list that would be run.
 *
 * @param {Runner} runner The current Protractor Runner.
 * @param {Array} specs Array of Directory Path Strings.
 * @return {q.Promise} Promise resolved with the test results
 */
exports.run = function (runner, specs) {

    var DaSpecConsoleRunner = require('daspec/src/console-runner'),
        execOptions = ['node', 'node_modules/.bin/daspec'],
        daspecResolvedRequire;

    if (runner.getConfig().daSpecOptions) {
        if (runner.getConfig().daSpecOptions.steps) {
            execOptions.push('--steps');
            execOptions.push(runner.getConfig().daSpecOptions.steps);
        }
    }
    execOptions = execOptions.concat(specs);

    function stepResult() {
        console.log('stepResult');
    }

    return runner.runTestPreparer().then(function () {
        return q.promise(function (resolve, reject) {
            config = {
                "encoding": "utf8",
                "formatters": ["../../../../node_modules/daspec/formatters/markdown-files", "../../../../node_modules/daspec/formatters/console"]
            };
            Object.keys(runner.getConfig().daSpecOptions).forEach(function (key) {
                config[key] = runner.getConfig().daSpecOptions[key];
            });
            var runtime = new ProtractorRunner(runner, config);
            var result = runtime.run();
            resolve({
                failedCount: failedCount,
                specResults: testResult
            });
        });
    });
};

/*global module, require */

var glob = require('glob'),
    DaSpec = require('daspec/node_modules/daspec-core'),
    vm = require('vm'),
    path = require('path'),
    fs = require('fs');
function ProtractorRunner(protractorRunner, config) {
    'use strict';
    var self = this,
        outputDir = config['output-dir'],
        fsOptions = {encoding: (config.encoding || 'utf8')},
        checkConfig = function () {
            if (!outputDir) {
                throw 'Output directory is not defined -- re-run with --help to see config arguments';
            }
            if (!config.specs || config.specs.length === 0) {
                throw 'No specs defined for this run -- re-run with --help to see config arguments';
            }
            if (!config.steps || config.steps.length === 0) {
                throw 'No steps defined for this run  -- re-run with --help to see config arguments';
            }
        },
        checkFiles = function (files) {
            if (files.steps.length === 0) {
                throw 'No step files match the list provided:' + config.steps;
            }
            if (files.specs.length === 0) {
                throw 'No spec files match the list provided:' + config.specs;
            }
        },
        toScript = function (sourcePath) {
            var source = fs.readFileSync(sourcePath, fsOptions);
            return new vm.Script(source, sourcePath);
        };
    self.run = function () {
        var files = {specs: [], steps: [], sources: []},
            sourceScripts,
            defineSteps = function () {
                sourceScripts.forEach(function (script) {
                    script.runInThisContext();
                });
                files.steps.forEach(function (filePath) {
                    require(path.resolve(filePath));
                });
            },
            runner,
            addFormatters = function () {
                config.formatters.forEach(function (module) {
                    require(module)(runner, config);
                });
            },
            globFiles = function () {
                Object.keys(files).forEach(function (key) {
                    if (config[key]) {
                        config[key].forEach(function (pattern) {
                            files[key] = files[key].concat(glob.sync(pattern));
                        });
                    }
                });
            },
            remapMatchers = function () {
                if (config.matchers) {
                    config.matchers = config.matchers.map(require);
                }
            },
            specs;
        checkConfig();
        globFiles();
        remapMatchers();
        checkFiles(files);
        var stepResults = {
            description: null,
            assertions: [],
            duration: 0
        };

        function specEnded(name, assertions) {
            var specInfo = {
                name: name,
                category: name
            };
            if (assertions.failed > 0) {
                failedCount += 1;
                protractorRunner.emit('testFail', specInfo);
            } else {
                protractorRunner.emit('testPass', specInfo);
            }
        }

        function allAssertionsPass(element, index, array) {
            return element === true;
        }

        function stepResult(result) {
            if (result.assertions.every(allAssertionsPass)) {
                stepResults.assertions.push({
                    passed: true
                });
            } else {
                stepResults.assertions.push({
                    passed: false,
                    errorMsg: 'this is my error message'
                });
            }
            testResult.push(stepResults)
        }

        specs = files.specs.map(function (specFile) {
            var getSource = function () {
                return fs.readFileSync(specFile, fsOptions);
            };
            return {name: specFile, content: getSource};
        });
        sourceScripts = files.sources.map(toScript);
        runner = new DaSpec.Runner(defineSteps, config);
        runner.addEventListener('stepResult', stepResult);
        runner.addEventListener('specEnded', specEnded);
        addFormatters();
        return runner.executeSuite(specs);
    };
};
gojko commented 9 years ago

I created a github repo for this, so we can collaborate on it rather than exchanging files through issues. You should have received an e-mail from github inviting you to the repo, if not, please let me know and i'll resend.

at first glance, I'd probably wire it up so the console runner is reused rather than reimplemented. you should be able to just wire things up by doing a replacement for this

https://github.com/daspec/daspec-js-npm/blob/master/lib/main.js

if that's not possible, we need to think about reorganising the console runner - because the intent was to reuse that class for many different ways of running daspec

philipbeadle commented 9 years ago

I tried that initially but couldnt figure a nice way to add the listeners to the runner so just reimplemented for now to check out how it might work. Totally agree that we should reuse the ConsoleRunner for the adapter. I've joined the organisation. Thanx

gojko commented 9 years ago

I'd probably do it in two steps

philipbeadle commented 9 years ago

I've uploaded a complete Angular project with my framework for DaSpec and a couple of simple steps. All seems to work well except I havent got the reporting back to DaSpec right as if a test fails the whole test suite falls over. Could you please have a look at what Ive built and let me know how to do the reporting part better. Cheers and thanx for the promises!

gojko commented 9 years ago

I've cloned the repo and tried running it, but some dependency is missing there. I'm getting this error

Running "concurrent:server" (concurrent) task Warning: Running "compass:server" (compass) task Warning: Command failed: /bin/sh -c compass --version /bin/sh: compass: command not found Use --force to continue.

I've installed compass using NPM, but that didn't help. Can you update the readme in the project with clean (from-scratch) install instructions so I can run it? then I'll be able to fix the problem

philipbeadle commented 9 years ago

Hi gojko, you just need to install the compass gem.

http://compass-style.org/install/

gojko commented 9 years ago

Hi,

I've tried my best to get this working, and I failed. I installed a ton of missing npm modules, I've even made the whole thing run, but it doesn't seem to kick off DaSpec. I'm giving up at this point - I just don't know enough about protractor to make it run. If you can create a completely clean install using npm, so I can just run npm install on a totally clean setup and npm test to run the whole thing, and it actually runs, I can look at it. Otherwise, we need to find someone who knows enough about protractor to set things up.

philipbeadle commented 9 years ago

to run the site use

grunt serve

then to run protractor use

node_modules/protractor/bin/protractor DaSpec/config.js

the config file tells protractor to use DaSpec as the runner and allows me to use protractor to access the pages.

philipbeadle commented 9 years ago

If that doesnt work right away lets do a team viewer session and Ill help you get sorted.

gojko commented 9 years ago

I'm getting this - so daspec isn't kicking off.

Starting selenium standalone server... [launcher] Running 1 instances of WebDriver Selenium standalone server started at http://10.0.2.21:58209/wd/hub http://localhost:9000/#/ Shutting down selenium standalone server. [launcher] 0 instance(s) of WebDriver still running [launcher] chrome #1 passed

Let's schedule a team viewer session to work on this together. I'm travelling over the next two weeks, but week starting 26th is OK. drop me an e-mail to gojko@neuri.co.uk so we can do this faster.

philipbeadle commented 8 years ago

Hi Gojko, Ive been away for a bit, can we sort out to do a catch up next week? Im on UTC+10 in Melbourne Australia.

Cheers Phil

gojko commented 8 years ago

Hi,

Please drop me an e-mail at gojko@neuri.co.uk so we can coordinate about this directly, github issues are a very slow way to communicate :)