🎨 elm-format

This commit is contained in:
Richard Feldman
2018-02-22 17:00:38 -05:00
parent 40c66a8a10
commit c8c89adc63
60 changed files with 4253 additions and 124 deletions

View File

@@ -0,0 +1,8 @@
# html-test-runner
Run elm-test suites in the browser
## Try it
1. `cd examples`
2. `elm-reactor`
3. Visit [http://localhost:8000/HtmlRunnerExample.elm](http://localhost:8000/HtmlRunnerExample.elm)

View File

@@ -0,0 +1,43 @@
sudo: false
cache:
directories:
- test/elm-stuff/build-artifacts
- sysconfcpus
os:
- linux
- osx
env:
matrix:
- ELM_VERSION=0.18.0 TARGET_NODE_VERSION=node
- ELM_VERSION=0.18.0 TARGET_NODE_VERSION=0.12
before_install:
- if [ ${TRAVIS_OS_NAME} == "osx" ];
then brew update; brew install nvm; mkdir ~/.nvm; export NVM_DIR=~/.nvm; source $(brew --prefix nvm)/nvm.sh;
fi
- | # epic build time improvement - see https://github.com/elm-lang/elm-compiler/issues/1473#issuecomment-245704142
if [ ! -d sysconfcpus/bin ];
then
git clone https://github.com/obmarg/libsysconfcpus.git;
cd libsysconfcpus;
./configure --prefix=$TRAVIS_BUILD_DIR/sysconfcpus;
make && make install;
cd ..;
fi
install:
- nvm install $TARGET_NODE_VERSION
- nvm use $TARGET_NODE_VERSION
- node --version
- npm --version
- npm install -g elm@$ELM_VERSION
- mv $(npm config get prefix)/bin/elm-make $(npm config get prefix)/bin/elm-make-old
- echo "#\!/bin/bash\\n\\necho \"Running elm-make with sysconfcpus -n 2\"\\n\\n$TRAVIS_BUILD_DIR/sysconfcpus/bin/sysconfcpus -n 2 elm-make-old \"\$@\"" > $(npm config get prefix)/bin/elm-make
- chmod +x $(npm config get prefix)/bin/elm-make
- npm install
script:
- npm test

View File

@@ -0,0 +1,47 @@
# node-test-runner [![Version](https://img.shields.io/npm/v/elm-test.svg)](https://www.npmjs.com/package/elm-test) [![Travis build Status](https://travis-ci.org/rtfeldman/node-test-runner.svg?branch=master)](http://travis-ci.org/rtfeldman/node-test-runner) [![AppVeyor build status](https://ci.appveyor.com/api/projects/status/fixcy4ko78di0l31/branch/master?svg=true)](https://ci.appveyor.com/project/rtfeldman/node-test-runner/branch/master)
Runs [elm-test](https://github.com/elm-community/elm-test) suites from Node.js
## Installation
```bash
npm install -g elm-test
```
## Usage
```bash
elm-test init # Adds the elm-test dependency and creates Main.elm and Tests.elm
elm-test # Runs the tests
```
Then add your tests to Tests.elm.
### Configuration
The `--compiler` flag can be used to use a version of the Elm compiler that
has not been install globally.
```
npm install elm
elm-test --compiler ./node_modules/.bin/elm-make
```
### Travis CI
If you want to run your tests on Travis CI, here's a good starter `.travis.yml`:
```yml
language: node_js
node_js:
- "5"
install:
- npm install -g elm
- npm install -g elm-test
- elm-package install -y
- pushd tests && elm-package install -y && popd
script:
- elm-test
```

View File

@@ -0,0 +1,25 @@
environment:
ELM_VERSION: "0.18.0"
matrix:
- nodejs_version: "5.0"
- nodejs_version: "0.12"
- nodejs_version: "0.11.13"
platform:
- x86
- x64
matrix:
fast_finish: true
install:
- ps: Update-NodeJsInstallation (Get-NodeJsLatestBuild $env:nodejs_version) $env:Platform
- node --version
- npm --version
- npm install -g elm@%ELM_VERSION%
- npm install
test_script:
- npm test
build: off

View File

@@ -0,0 +1,322 @@
#!/usr/bin/env node
var processTitle = "elm-test";
process.title = processTitle;
var compile = require("node-elm-compiler").compile,
fs = require("fs-extra"),
chalk = require("chalk"),
path = require("path"),
temp = require("temp").track(), // Automatically cleans up temp files.
util = require("util"),
_ = require("lodash"),
spawn = require("cross-spawn"),
minimist = require("minimist"),
firstline = require("firstline"),
findUp = require("find-up"),
chokidar = require("chokidar");
var elm = {
'elm-package': 'elm-package'
};
var args = minimist(process.argv.slice(2), {
alias: {
'help': 'h',
'yes': 'y',
'seed': 's',
'compiler': 'c',
'report': 'r',
'watch': 'w'
},
boolean: [ 'yes', 'warn', 'version', 'help', 'watch' ],
string: [ 'compiler', 'seed', 'report' ]
});
if (args.help) {
console.log("Usage: elm-test init [--yes] # Create example tests\n");
console.log("Usage: elm-test TESTFILE [--compiler /path/to/compiler] # Run TESTFILE\n");
console.log("Usage: elm-test [--compiler /path/to/compiler] # Run tests/Main.elm\n");
console.log("Usage: elm-test [--seed integer] # Run with initial fuzzer seed\n");
console.log("Usage: elm-test [--report json or chalk (default)] # Print results to stdout in given format\n");
console.log("Usage: elm-test [--watch] # Run tests on file changes\n");
process.exit(1);
}
if (args.version) {
console.log(require(path.join(__dirname, "..", "package.json")).version);
process.exit(0);
}
var report = "chalk";
if (args.report !== undefined) {
report = args.report;
}
checkNodeVersion();
function checkNodeVersion() {
var nodeVersionString = process.versions.node;
var nodeVersion = _.map(_.split(nodeVersionString, '.'), _.parseInt);
if((nodeVersion[0] === 0 && nodeVersion[1] < 11) ||
(nodeVersion[0] === 0 && nodeVersion[1] === 11 && nodeVersion[2] < 13)) {
console.log("using node v" + nodeVersionString);
console.error("elm-test requires node v0.11.13 or greater - upgrade the installed version of node and try again");
process.exit(1);
}
}
if (args._[0] == "init") {
var copyTemplate = function(templateName, destName) {
if (arguments.length == 1) {
destName = templateName;
}
var source = path.resolve(__dirname, "../templates/" + templateName);
var destination = path.resolve("tests", destName);
if (fs.existsSync(destination)) {
console.log(destination + " already exists");
} else {
fs.copySync(source, destination);
console.log("Created " + destination);
}
};
var ensureDirectory = function(dirName) {
var destination = path.resolve(".", dirName);
if (fs.existsSync(destination)) {
console.log(destination + " already exists");
} else {
fs.mkdirSync(destination);
console.log("Created " + destination);
}
};
var elmOptions = "";
if (args.yes) {
elmOptions += " --yes";
}
ensureDirectory("src");
ensureDirectory("tests");
copyTemplate("elm-package.json");
copyTemplate("Main.elm");
copyTemplate("Tests.elm");
copyTemplate("gitignore", ".gitignore");
process.exit(0);
}
function evalElmCode (compiledCode, testModuleName) {
var Elm = function(module) { eval(compiledCode); return module.exports; }({});
// Make sure necessary things are defined.
if (typeof Elm === 'undefined') { throw 'elm-io config error: Elm is not defined. Make sure you provide a file compiled by Elm!'; }
function getTestModule() {
var module = Elm;
var moduleParts = testModuleName.split('.');
while (moduleParts.length) {
var modulePart = moduleParts.shift();
if (module[modulePart] === undefined) {
return undefined;
}
module = module[modulePart];
}
return module;
}
var testModule = getTestModule();
if (testModule === undefined) { throw 'Elm.' + testModuleName + ' is not defined. Make sure you provide a file compiled by Elm!'; }
var initialSeed = null;
if (args.seed !== undefined) {
initialSeed = args.seed;
}
// Apply Node polyfills as necessary.
var window = {Date: Date, addEventListener: function() {}, removeEventListener: function() {}};
var document = {body: {}, createTextNode: function() {}};
pathToMake = args.compiler;
if (typeof XMLHttpRequest === 'undefined') { XMLHttpRequest = function() { return { addEventListener: function() {}, open: function() {}, send: function() {} }; }; }
if (typeof FormData === 'undefined') { FormData = function () { this._data = []; }; FormData.prototype.append = function () { this._data.push(Array.prototype.slice.call(arguments)); }; }
// Fix Windows Unicode problems. Credit to https://github.com/sindresorhus/figures for the Windows compat idea!
var windowsSubstitutions = [[/[↓✗►]/g, '>'], [/╵│╷╹┃╻/g, '|'], [/═/g, '='],, [/▔/g, '-'], [/✔/g, '√']];
function windowsify(str) {
return windowsSubstitutions.reduce(
function(result, sub) { return result.replace(sub[0], sub[1]); }, str);
}
function chalkify(messages) {
return messages.map(function(msg) {
var path = msg.styles;
var text = process.platform === 'win32' ? windowsify(msg.text) : msg.text;
if (path.length === 0) {
return text;
} else {
var fn = chalk;
path.forEach(function(nextPath) { fn = fn[nextPath]; });
return fn(text);
}
}).join('');
}
// Run the Elm app.
var app = testModule.worker({seed: initialSeed, report: report});
// Receive messages from ports and translate them into appropriate JS calls.
app.ports.emit.subscribe(function(msg) {
var msgType = msg[0];
var data = msg[1];
if (msgType === 'FINISHED') {
if (data.format === "CHALK") {
console.log(chalkify(data.message));
} else {
console.log(JSON.stringify(data.message));
}
if (!args.watch) {
process.exit(data.exitCode);
}
} else if (msgType === "STARTED" || msgType === "TEST_COMPLETED") {
if (data.format === "CHALK") {
console.log(chalkify(data.message));
} else {
console.log(JSON.stringify(data.message));
}
}
});
}
var testFile = args._[0],
cwd = __dirname,
pathToMake = undefined;
function spawnCompiler(cmd, args, opts) {
var compilerOpts =
_.defaults({stdio: [process.stdin, report === "chalk" ? process.stdout : 'ignore', process.stderr] }, opts);
return spawn(cmd, args, compilerOpts);
}
if (typeof testFile == "undefined") {
testFile = "tests/Main.elm";
}
if (args.compiler !== undefined) {
pathToMake = args.compiler;
if (!pathToMake) {
console.error("The --compiler option must be given a path to an elm-make executable.");
process.exit(1);
}
}
if (!fs.existsSync(testFile)) {
console.error("Could not find file " + testFile);
process.exit(1);
}
var testModulePromise = firstline(testFile).then(function (testModuleLine) {
var moduleMatches = testModuleLine.match(/^(?:port\s+)?module\s+([^\s]+)/);
if (moduleMatches) {
return moduleMatches[1];
}
return 'Main';
});
function infoLog(msg) {
if (report === "chalk") {
console.log(msg);
}
}
findUp('elm-package.json', { cwd: path.dirname(testFile) })
.then(function (elmPackagePath) {
var elmRootDir = path.dirname(elmPackagePath);
if (fs.realpathSync(elmRootDir) !== fs.realpathSync(process.cwd())) {
testFile = path.relative(elmRootDir, testFile);
process.chdir(elmRootDir);
}
if (args.watch) {
infoLog('Running in watch mode');
var watcher = chokidar.watch('**/*.elm', { ignoreInitial: true });
var eventNameMap = {
add: 'added',
addDir: 'added',
change: 'changed',
unlink: 'removed',
unlinkDir: 'removed',
};
watcher.on('all', function (event, filePath) {
var relativePath = path.relative(elmRootDir, filePath);
var eventName = eventNameMap[event] || event;
infoLog('\n' + relativePath + ' ' + eventName + '. Rebuilding!');
runTests();
});
}
function runTests () {
temp.open({ prefix:'elm_test_', suffix:'.js' }, function(err, info) {
var dest = info.path;
var compileProcess = compile( [testFile], {
output: dest,
verbose: args.verbose,
yes: true,
spawn: spawnCompiler,
pathToMake: pathToMake,
warn:args.warn
});
compileProcess.on('close', function(exitCode) {
if (exitCode !== 0) {
console.error("Compilation failed for", testFile);
if (!args.watch) {
process.exit(exitCode);
}
} else {
testModulePromise.then(function (testModuleName) {
evalElmCode(fs.readFileSync(dest, {encoding: "utf8"}), testModuleName);
});
}
});
});
}
runTests();
});
process.on('uncaughtException', function(error) {
if (/ an argument in Javascript/.test(error)) {
// Handle arg mismatch between js and elm code. Expected message from Elm:
// "You are giving module `Main` an argument in JavaScript.
// This module does not take arguments though! You probably need to change the
// initialization code to something like `Elm.Main.fullscreen()`]"
console.error("Error starting the node-test-runner.");
console.error("Please check your Javascript 'elm-test' and Elm 'node-test-runner' package versions are compatible");
} else {
console.error("Unhandled exception while running the tests:", error);
}
});