Initial work on in-browser test runner
Run `grunt test` and open up the `build/test/index.html` to run the tests.feature-extract-files
parent
92bd2c921e
commit
500522bdeb
83
Gruntfile.js
83
Gruntfile.js
|
@ -9,6 +9,10 @@ module.exports = function(grunt) {
|
||||||
"A persistent task which creates a development build whenever source files are modified.",
|
"A persistent task which creates a development build whenever source files are modified.",
|
||||||
["clean:dev", "concat:css", "concat:js", "copy:htmlDev", "copy:staticDev", "chmod:build", "watch"]);
|
["clean:dev", "concat:css", "concat:js", "copy:htmlDev", "copy:staticDev", "chmod:build", "watch"]);
|
||||||
|
|
||||||
|
grunt.registerTask("test",
|
||||||
|
"A persistent task which creates a test build whenever source files are modified.",
|
||||||
|
["clean:dev", "concat:cssTest", "concat:jsTest", "copy:htmlTest", "copy:staticTest", "chmod:build", "watch"]);
|
||||||
|
|
||||||
grunt.registerTask("prod",
|
grunt.registerTask("prod",
|
||||||
"Creates a production-ready build. Use the --msg flag to add a compile message.",
|
"Creates a production-ready build. Use the --msg flag to add a compile message.",
|
||||||
["eslint", "exec:stats", "clean", "jsdoc", "concat", "copy:htmlDev", "copy:htmlProd", "copy:htmlInline",
|
["eslint", "exec:stats", "clean", "jsdoc", "concat", "copy:htmlDev", "copy:htmlProd", "copy:htmlInline",
|
||||||
|
@ -50,7 +54,7 @@ module.exports = function(grunt) {
|
||||||
|
|
||||||
|
|
||||||
// JS includes
|
// JS includes
|
||||||
var jsFiles = [
|
var jsIncludes = [
|
||||||
// Third party framework libraries
|
// Third party framework libraries
|
||||||
"src/js/lib/jquery-2.1.1.js",
|
"src/js/lib/jquery-2.1.1.js",
|
||||||
"src/js/lib/bootstrap-3.3.6.js",
|
"src/js/lib/bootstrap-3.3.6.js",
|
||||||
|
@ -154,10 +158,27 @@ module.exports = function(grunt) {
|
||||||
"src/js/views/html/*.js",
|
"src/js/views/html/*.js",
|
||||||
"!src/js/views/html/main.js",
|
"!src/js/views/html/main.js",
|
||||||
|
|
||||||
// Start the app!
|
|
||||||
"src/js/views/html/main.js",
|
|
||||||
];
|
];
|
||||||
|
|
||||||
|
var jsAppFiles = [].concat(
|
||||||
|
jsIncludes,
|
||||||
|
[
|
||||||
|
// Start the main app!
|
||||||
|
"src/js/views/html/main.js",
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
var jsTestFiles = [].concat(
|
||||||
|
jsIncludes,
|
||||||
|
[
|
||||||
|
"src/js/lib/vuejs/vue.min.js",
|
||||||
|
"src/js/test/*.js",
|
||||||
|
"src/js/test/tests/**/*",
|
||||||
|
// Start the test runner app!
|
||||||
|
"src/js/test/views/html/main.js",
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
var banner = '/**\n\
|
var banner = '/**\n\
|
||||||
* CyberChef - The Cyber Swiss Army Knife\n\
|
* CyberChef - The Cyber Swiss Army Knife\n\
|
||||||
*\n\
|
*\n\
|
||||||
|
@ -198,6 +219,7 @@ module.exports = function(grunt) {
|
||||||
config: ["src/js/config/**/*.js"],
|
config: ["src/js/config/**/*.js"],
|
||||||
views: ["src/js/views/**/*.js"],
|
views: ["src/js/views/**/*.js"],
|
||||||
operations: ["src/js/operations/**/*.js"],
|
operations: ["src/js/operations/**/*.js"],
|
||||||
|
tests: ["src/js/test/**/*.js"],
|
||||||
},
|
},
|
||||||
jsdoc: {
|
jsdoc: {
|
||||||
options: {
|
options: {
|
||||||
|
@ -239,12 +261,35 @@ module.exports = function(grunt) {
|
||||||
],
|
],
|
||||||
dest: "build/dev/styles.css"
|
dest: "build/dev/styles.css"
|
||||||
},
|
},
|
||||||
|
cssTest: {
|
||||||
|
options: {
|
||||||
|
banner: banner.replace(/\/\*\*/g, "/*!"),
|
||||||
|
process: function(content, srcpath) {
|
||||||
|
// Change special comments from /** to /*! to comply with cssmin
|
||||||
|
content = content.replace(/^\/\*\* /g, "/*! ");
|
||||||
|
return grunt.template.process(content);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
src: [
|
||||||
|
"src/css/lib/**/*.css",
|
||||||
|
"src/css/structure/**/*.css",
|
||||||
|
"src/css/themes/classic.css"
|
||||||
|
],
|
||||||
|
dest: "build/test/styles.css"
|
||||||
|
},
|
||||||
js: {
|
js: {
|
||||||
options: {
|
options: {
|
||||||
banner: '"use strict";\n'
|
banner: '"use strict";\n'
|
||||||
},
|
},
|
||||||
src: jsFiles,
|
src: jsAppFiles,
|
||||||
dest: "build/dev/scripts.js"
|
dest: "build/dev/scripts.js"
|
||||||
|
},
|
||||||
|
jsTest: {
|
||||||
|
options: {
|
||||||
|
banner: '"use strict";\n'
|
||||||
|
},
|
||||||
|
src: jsTestFiles,
|
||||||
|
dest: "build/test/scripts.js"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
copy: {
|
copy: {
|
||||||
|
@ -257,6 +302,15 @@ module.exports = function(grunt) {
|
||||||
src: "src/html/index.html",
|
src: "src/html/index.html",
|
||||||
dest: "build/dev/index.html"
|
dest: "build/dev/index.html"
|
||||||
},
|
},
|
||||||
|
htmlTest: {
|
||||||
|
options: {
|
||||||
|
process: function(content, srcpath) {
|
||||||
|
return grunt.template.process(content, templateOptions);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
src: "src/html/test.html",
|
||||||
|
dest: "build/test/index.html"
|
||||||
|
},
|
||||||
htmlProd: {
|
htmlProd: {
|
||||||
options: {
|
options: {
|
||||||
process: function(content, srcpath) {
|
process: function(content, srcpath) {
|
||||||
|
@ -294,6 +348,21 @@ module.exports = function(grunt) {
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
staticTest: {
|
||||||
|
files: [
|
||||||
|
{
|
||||||
|
expand: true,
|
||||||
|
cwd: "src/static/",
|
||||||
|
src: [
|
||||||
|
"**/*",
|
||||||
|
"**/.*",
|
||||||
|
"!stats.txt",
|
||||||
|
"!ga.html"
|
||||||
|
],
|
||||||
|
dest: "build/test/"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
staticProd: {
|
staticProd: {
|
||||||
files: [
|
files: [
|
||||||
{
|
{
|
||||||
|
@ -468,15 +537,15 @@ module.exports = function(grunt) {
|
||||||
},
|
},
|
||||||
js: {
|
js: {
|
||||||
files: "src/js/**/*.js",
|
files: "src/js/**/*.js",
|
||||||
tasks: ["concat:js", "chmod:build"]
|
tasks: ["concat:js", "concat:jsTest", "chmod:build"]
|
||||||
},
|
},
|
||||||
html: {
|
html: {
|
||||||
files: "src/html/**/*.html",
|
files: "src/html/**/*.html",
|
||||||
tasks: ["copy:htmlDev", "chmod:build"]
|
tasks: ["copy:htmlDev", "copy:htmlTest", "chmod:build"]
|
||||||
},
|
},
|
||||||
static: {
|
static: {
|
||||||
files: ["src/static/**/*", "src/static/**/.*"],
|
files: ["src/static/**/*", "src/static/**/.*"],
|
||||||
tasks: ["copy:staticDev", "chmod:build"]
|
tasks: ["copy:staticDev", "copy:staticTest", "chmod:build"]
|
||||||
},
|
},
|
||||||
grunt: {
|
grunt: {
|
||||||
files: "Gruntfile.js",
|
files: "Gruntfile.js",
|
||||||
|
|
|
@ -0,0 +1,96 @@
|
||||||
|
<!-- htmlmin:ignore --><!--
|
||||||
|
CyberChef - The Cyber Swiss Army Knife
|
||||||
|
|
||||||
|
@author tlwr [toby@toby.codes]
|
||||||
|
|
||||||
|
@copyright Crown Copyright 2017
|
||||||
|
@license Apache-2.0
|
||||||
|
|
||||||
|
Copyright 2017 Crown Copyright
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
-->
|
||||||
|
<!-- htmlmin:ignore -->
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>CyberChef Test Runner</title>
|
||||||
|
<link rel="icon" type="image/png" href="images/favicon.ico?__inline" />
|
||||||
|
<link href="styles.css" rel="stylesheet" />
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<template id="test-status-icon-template">
|
||||||
|
<span>{{ getIcon() }}</span>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template id="test-stats-template">
|
||||||
|
<div class="text-center row">
|
||||||
|
<div class="col-md-2"
|
||||||
|
v-for="status in ['Waiting', 'Loading', 'Erroring', 'Failing']">
|
||||||
|
<test-status-icon :status="status.toLowerCase()"></test-status-icon>
|
||||||
|
<br>
|
||||||
|
{{ status }}
|
||||||
|
<br>
|
||||||
|
{{ countTestsWithStatus(status.toLowerCase()) }}
|
||||||
|
</div>
|
||||||
|
<div class="col-md-2">
|
||||||
|
<test-status-icon status="passing"></test-status-icon>
|
||||||
|
<br>
|
||||||
|
Passing
|
||||||
|
<br>
|
||||||
|
{{ countTestsWithStatus("passing") }}
|
||||||
|
/
|
||||||
|
{{ tests.length }}
|
||||||
|
</div>
|
||||||
|
<div class="col-md-2">
|
||||||
|
<test-status-icon status="passing"></test-status-icon>
|
||||||
|
<br>
|
||||||
|
% Passing
|
||||||
|
<br>
|
||||||
|
{{ ((100.0 * countTestsWithStatus("passing")) / tests.length).toFixed(1) }}%
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template id="tests-template">
|
||||||
|
<table class="table table-striped">
|
||||||
|
<tbody>
|
||||||
|
<tr v-for="test in tests">
|
||||||
|
<td class="col-md-1 col-sm-4">
|
||||||
|
<test-status-icon :status="test.status"></test-status-icon>
|
||||||
|
</td>
|
||||||
|
<td class="col-md-4 col-sm-8">
|
||||||
|
{{ test.name }}
|
||||||
|
</td>
|
||||||
|
<td class="col-md-7 col-sm-12">
|
||||||
|
<pre v-if="test.output"><code>{{ test.output }}</code></pre>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<div class="container">
|
||||||
|
<main>
|
||||||
|
<h1>CyberChef Test Runner</h1>
|
||||||
|
<hr>
|
||||||
|
<test-stats :tests="tests"></test-stats>
|
||||||
|
<hr>
|
||||||
|
<tests :tests="tests"></tests>
|
||||||
|
</main>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script type="application/javascript" src="scripts.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -109,6 +109,10 @@
|
||||||
"OutputWaiter": false,
|
"OutputWaiter": false,
|
||||||
"RecipeWaiter": false,
|
"RecipeWaiter": false,
|
||||||
"SeasonalWaiter": false,
|
"SeasonalWaiter": false,
|
||||||
"WindowWaiter": false
|
"WindowWaiter": false,
|
||||||
|
|
||||||
|
/* test */
|
||||||
|
"Vue": false,
|
||||||
|
"TestRegister": false
|
||||||
}
|
}
|
||||||
}
|
}
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,97 @@
|
||||||
|
/**
|
||||||
|
* TestRegister.js
|
||||||
|
*
|
||||||
|
* This is so individual files can register their tests in one place, and
|
||||||
|
* ensure that they will get run by the frontend.
|
||||||
|
*
|
||||||
|
* @author tlwr [toby@toby.codes
|
||||||
|
*
|
||||||
|
* @copyright Crown Copyright 2017
|
||||||
|
* @license Apache-2.0
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
(function() {
|
||||||
|
/**
|
||||||
|
* Add a list of tests to the register.
|
||||||
|
*
|
||||||
|
* @class
|
||||||
|
*/
|
||||||
|
function TestRegister() {
|
||||||
|
this.tests = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add a list of tests to the register.
|
||||||
|
*
|
||||||
|
* @param {Object[]} tests
|
||||||
|
*/
|
||||||
|
TestRegister.prototype.addTests = function(tests) {
|
||||||
|
this.tests = this.tests.concat(tests.map(function(test) {
|
||||||
|
|
||||||
|
test.status = "waiting";
|
||||||
|
test.output = "";
|
||||||
|
|
||||||
|
return test;
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the list of tests.
|
||||||
|
*
|
||||||
|
* @returns {Object[]} tests
|
||||||
|
return this.tests;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runs all the tests in the register and updates the state of each test.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
TestRegister.prototype.runTests = function() {
|
||||||
|
this.tests.forEach(function(test, i) {
|
||||||
|
var chef = new Chef();
|
||||||
|
|
||||||
|
// This resolve is to not instantly break when async operations are
|
||||||
|
// supported. Marked as TODO.
|
||||||
|
Promise.resolve(chef.bake(
|
||||||
|
test.input,
|
||||||
|
test.recipeConfig,
|
||||||
|
{},
|
||||||
|
0,
|
||||||
|
0
|
||||||
|
))
|
||||||
|
.then(function(result) {
|
||||||
|
if (result.error) {
|
||||||
|
if (test.expectedError) {
|
||||||
|
test.status = "passing";
|
||||||
|
} else {
|
||||||
|
test.status = "erroring";
|
||||||
|
test.output = [
|
||||||
|
"Erroring",
|
||||||
|
"-------",
|
||||||
|
result.error.displayStr,
|
||||||
|
].join("\n");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (result.result === test.expectedOutput) {
|
||||||
|
test.status = "passing";
|
||||||
|
} else {
|
||||||
|
test.status = "failing";
|
||||||
|
test.output = [
|
||||||
|
"Failing",
|
||||||
|
"-------",
|
||||||
|
"Expected",
|
||||||
|
"-------",
|
||||||
|
test.expectedOutput,
|
||||||
|
"Actual",
|
||||||
|
"-------",
|
||||||
|
result.result,
|
||||||
|
].join("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Singleton TestRegister, keeping things simple and obvious.
|
||||||
|
window.TestRegister = new TestRegister();
|
||||||
|
})();
|
|
@ -0,0 +1,84 @@
|
||||||
|
/**
|
||||||
|
* Core tests.
|
||||||
|
*
|
||||||
|
* @copyright Crown Copyright 2017
|
||||||
|
* @license Apache-2.0
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
TestRegister.addTests([
|
||||||
|
{
|
||||||
|
name: "Example error",
|
||||||
|
input: "1\n2\na\n4",
|
||||||
|
expectedOutput: "1\n2\n3\n4",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "Fork",
|
||||||
|
args: ["\n", "\n", false],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
op: "To Base",
|
||||||
|
args: [16],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Example fail",
|
||||||
|
input: "1\n2\na\n4",
|
||||||
|
expectedOutput: "1\n2\n3\n4",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "Fork",
|
||||||
|
args: ["\n", "\n", true],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
op: "To Base",
|
||||||
|
args: [16],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Fork: nothing",
|
||||||
|
input: "",
|
||||||
|
expectedOutput: "",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "Fork",
|
||||||
|
args: ["\n", "\n", false],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Fork, Merge: nothing",
|
||||||
|
input: "",
|
||||||
|
expectedOutput: "",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "Fork",
|
||||||
|
args: ["\n", "\n", false],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
op: "Merge",
|
||||||
|
args: [],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Fork, (expect) Error, Merge",
|
||||||
|
input: "1\n2\na\n4",
|
||||||
|
expectedError: true,
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "Fork",
|
||||||
|
args: ["\n", "\n", false],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
op: "To Base",
|
||||||
|
args: [16],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
op: "Merge",
|
||||||
|
args: [],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
]);
|
|
@ -0,0 +1,77 @@
|
||||||
|
/**
|
||||||
|
* Base58 tests.
|
||||||
|
*
|
||||||
|
* @author tlwr [toby@toby.codes
|
||||||
|
*
|
||||||
|
* @copyright Crown Copyright 2017
|
||||||
|
* @license Apache-2.0
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
TestRegister.addTests([
|
||||||
|
{
|
||||||
|
name: "To Base58 (Bitcoin): nothing",
|
||||||
|
input: "",
|
||||||
|
expectedOutput: "",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "To Base58",
|
||||||
|
args: ["123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "To Base58 (Ripple): nothing",
|
||||||
|
input: "",
|
||||||
|
expectedOutput: "",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "To Base58",
|
||||||
|
args: ["rpshnaf39wBUDNEGHJKLM4PQRST7VWXYZ2bcdeCg65jkm8oFqi1tuvAxyz"],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "To Base58 (Bitcoin): 'hello world'",
|
||||||
|
input: "hello world",
|
||||||
|
expectedOutput: "StV1DL6CwTryKyV",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "To Base58",
|
||||||
|
args: ["123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "To Base58 (Ripple): 'hello world'",
|
||||||
|
input: "hello world",
|
||||||
|
expectedOutput: "StVrDLaUATiyKyV",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "To Base58",
|
||||||
|
args: ["rpshnaf39wBUDNEGHJKLM4PQRST7VWXYZ2bcdeCg65jkm8oFqi1tuvAxyz"],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "From Base58 (Bitcoin): 'StV1DL6CwTryKyV'",
|
||||||
|
input: "StV1DL6CwTryKyV",
|
||||||
|
expectedOutput: "hello world",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "From Base58",
|
||||||
|
args: ["123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "From Base58 (Ripple): 'StVrDLaUATiyKyV'",
|
||||||
|
input: "StVrDLaUATiyKyV",
|
||||||
|
expectedOutput: "hello world",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "From Base58",
|
||||||
|
args: ["rpshnaf39wBUDNEGHJKLM4PQRST7VWXYZ2bcdeCg65jkm8oFqi1tuvAxyz"],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
]);
|
|
@ -0,0 +1,33 @@
|
||||||
|
/**
|
||||||
|
* Base58 tests.
|
||||||
|
*
|
||||||
|
* @author tlwr [toby@toby.codes
|
||||||
|
*
|
||||||
|
* @copyright Crown Copyright 2017
|
||||||
|
* @license Apache-2.0
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
TestRegister.addTests([
|
||||||
|
{
|
||||||
|
name: "To Morse Code: 'SOS'",
|
||||||
|
input: "SOS",
|
||||||
|
expectedOutput: "... --- ...",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "To Morse Code",
|
||||||
|
args: ["-/.", "Space", "Line feed"],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "From Morse Code '... --- ...'",
|
||||||
|
input: "... --- ...",
|
||||||
|
expectedOutput: "SOS",
|
||||||
|
recipeConfig: [
|
||||||
|
{
|
||||||
|
op: "From Morse Code",
|
||||||
|
args: ["Space", "Line feed"],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
]);
|
|
@ -0,0 +1,58 @@
|
||||||
|
/**
|
||||||
|
* main.js
|
||||||
|
*
|
||||||
|
* Simple VueJS app for running all the tests and displaying some basic stats.
|
||||||
|
* @author tlwr [toby@toby.codes]
|
||||||
|
* @copyright Crown Copyright 2017
|
||||||
|
* @license Apache-2.0
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
(function() {
|
||||||
|
Vue.component("test-status-icon", {
|
||||||
|
template: "#test-status-icon-template",
|
||||||
|
props: ["status"],
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
getIcon: function() {
|
||||||
|
var icons = {
|
||||||
|
waiting: "⌚",
|
||||||
|
loading: "⚡",
|
||||||
|
passing: "✔️️",
|
||||||
|
failing: "❌",
|
||||||
|
erroring: "☠️",
|
||||||
|
};
|
||||||
|
|
||||||
|
return icons[this.status];
|
||||||
|
}
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
Vue.component("test-stats", {
|
||||||
|
template: "#test-stats-template",
|
||||||
|
props: ["tests"],
|
||||||
|
|
||||||
|
methods: {
|
||||||
|
countTestsWithStatus: function(status) {
|
||||||
|
return this.tests.filter(function(test) {
|
||||||
|
return test.status === status;
|
||||||
|
}).length;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
Vue.component("tests", {
|
||||||
|
template: "#tests-template",
|
||||||
|
props: ["tests"],
|
||||||
|
});
|
||||||
|
|
||||||
|
window.TestRunner = new Vue({
|
||||||
|
el: "main",
|
||||||
|
data: {
|
||||||
|
tests: TestRegister.getTests(),
|
||||||
|
},
|
||||||
|
|
||||||
|
mounted: function() {
|
||||||
|
TestRegister.runTests();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
})();
|
Loading…
Reference in New Issue