Skip to content

Instantly share code, notes, and snippets.

@mathdoodle
Last active January 13, 2021 03:49
Show Gist options
  • Save mathdoodle/503088539925cafcb597d71c312c082a to your computer and use it in GitHub Desktop.
Save mathdoodle/503088539925cafcb597d71c312c082a to your computer and use it in GitHub Desktop.
Tutorial

Getting Started with STEMCstudio

Overview

This brief example demonstrates some Best Practices for developing your programs:

  • Modularity,
  • Documentation, and
  • Unit Testing.

It also explains how the various files work together.

For information on specific libraries, e.g. WebGL Graphics and Geometric Algebra, please see the examples and consult the links in the Properties menu.

Modularity

It is extremely beneficial to be able to split your application or library into multiple files, each with a cohesive purpose. Up until recently, re-assembling them in JavaScript was error prone because of the need to manually manage file dependencies. But no more! The ES6 modules specification allows you to easily describe the dependencies between the modules that comprise your application so that the system-wide module loader, System can load them strictly according to their dependencies.

Documentaion

Documentation of your software can take many forms. STEMCstudio supports the Markdown format making it easy to create application- or library-level documentation. The contents of the README.md file, transpiled to HTML, are displayed while your application is not running. The README.md file is also a prominent artifact in GitHub.

Unit Testing

Unit Testing is supported using Jasmine.

How It Works

index.html

You may define many views in one project, but this file is recognized by name as the default view.

Your ES6 modules are inserted at the // CODE-MARKER.

Importing your top-level module, e.g. index.js using

System.import('./index.js')

will begin the execution of your program.

The System module loader will manage dependencies for you through import and export statements.

index.ts

Notice how it imports its dependencies and how they are exported from other files.

style.css

The contents of this file are inserted into index.html at the /* STYLE-MARKER */.

Dependencies

External dependencies are defined using the Properties menu and are included as <script> elements at the <!--- SCRIPTS-MARKER -->.

You may add other external dependencies directly to the index.html file.

README.md

Refer to the README.md file to see how the following HTML was created.

#h1 ##h2 ###h3 ####h4

emphasis

bold

code

MathJax: \[\nabla M \ne 0\]

Copyright (c) 2016 David Geo Holmes.

export default function() {
describe("...", function() {
it("should ...", function() {
expect(true).toBeTruthy()
})
})
}
<!DOCTYPE html>
<html>
<head>
<script src="https://jspm.io/system.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jasmine/3.4.0/jasmine.css">
<script src="https://www.stemcstudio.com:/vendor/[email protected]/domready.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/3.4.0/jasmine.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/3.4.0/jasmine-html.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/stats.js/r16/Stats.min.js"></script>
</head>
<body>
<script>
System.config({
"warnings": false,
"map": {
"davinci-eight": "https://unpkg.com/[email protected]/build/browser/index.js"
}
});
</script>
<canvas id="canvas"></canvas>
<script>
System.register('./Example.spec.js', [], function (exports_1, context_1) {
'use strict';
var __moduleName = context_1 && context_1.id;
function default_1() {
describe('...', function () {
it('should ...', function () {
expect(true).toBeTruthy();
});
});
}
exports_1('default', default_1);
return {
setters: [],
execute: function () {
}
};
});
System.register('./index.js', ['davinci-eight'], function (exports_1, context_1) {
'use strict';
var EIGHT, engine, scene, ambients, camera, dirLight, trackball, body, stats, animate;
var __moduleName = context_1 && context_1.id;
return {
setters: [function (EIGHT_1) {
EIGHT = EIGHT_1;
}],
execute: function () {
engine = new EIGHT.Engine('canvas').size(500, 500).clearColor(0.1, 0.1, 0.1, 1).enable(EIGHT.Capability.DEPTH_TEST);
scene = new EIGHT.Scene(engine);
ambients = [];
camera = new EIGHT.PerspectiveCamera();
camera.eye.scale(5);
ambients.push(camera);
dirLight = new EIGHT.DirectionalLight();
ambients.push(dirLight);
trackball = new EIGHT.TrackballControls(camera, window);
trackball.subscribe(engine.canvas);
trackball.noPan = true;
body = new EIGHT.Box(engine, { color: EIGHT.Color.blueviolet });
scene.add(body);
stats = new Stats();
document.body.appendChild(stats.domElement);
animate = function (_timestamp) {
stats.begin();
engine.clear();
trackball.update();
dirLight.direction.copy(camera.look).sub(camera.eye);
scene.render(ambients);
stats.end();
requestAnimationFrame(animate);
};
requestAnimationFrame(animate);
}
};
});
System.register('./tests.spec.js', [], function (exports_1, context_1) {
'use strict';
var __moduleName = context_1 && context_1.id;
function spec() {
describe('example', function () {
it('should pass', function () {
expect(true).toBeTruthy();
});
});
}
exports_1('spec', spec);
return {
setters: [],
execute: function () {
}
};
});
System.register('./tests.js', ['./tests.spec.js'], function (exports_1, context_1) {
'use strict';
var tests_spec_1, HtmlReporter, config, specifications;
var __moduleName = context_1 && context_1.id;
function getContainer() {
var element = document.body;
return element;
}
function onChangeOption(key, value) {
switch (key) {
case 'failFast': {
config.failFast = !config.failFast;
break;
}
case 'throwFailures': {
config.oneFailurePerSpec = !config.oneFailurePerSpec;
break;
}
case 'random': {
config.random = !config.random;
break;
}
case 'hideDisabled': {
config.hideDisabled = !config.hideDisabled;
break;
}
default: {
console.warn('navigateWithNewParam(key=' + key + ', value=' + JSON.stringify(value));
}
}
runTests();
}
function addSpec(value) {
specifications.push(value);
return '';
}
function addSeed(_seed) {
return '';
}
function runTests() {
var jasmineCore = jasmineRequire.core(jasmineRequire);
jasmineRequire.html(jasmineCore);
var env = jasmineCore.getEnv();
var jasmineInterface = jasmineRequire.interface(jasmineCore, env);
extend(window, jasmineInterface);
var htmlReporter = new HtmlReporter({
env: env,
addToExistingQueryString: function (key, value) {
switch (key) {
case 'spec': {
return addSpec(value);
break;
}
case 'seed': {
return addSeed(parseInt(value, 10));
break;
}
default: {
throw new Error('Unknown key: ' + key);
}
}
},
navigateWithNewParam: onChangeOption,
getContainer: getContainer,
createElement: function () {
return document.createElement.apply(document, arguments);
},
createTextNode: function () {
return document.createTextNode.apply(document, arguments);
},
timer: new jasmine.Timer(),
filterSpecs: true
});
env.addReporter(jasmineInterface.jsApiReporter);
env.addReporter(htmlReporter);
env.configure(config);
htmlReporter.initialize();
describe('spec', tests_spec_1.spec);
env.execute();
}
function extend(destination, source) {
for (var property in source) {
if (source.hasOwnProperty(property)) {
destination[property] = source[property];
}
}
return destination;
}
return {
setters: [function (tests_spec_1_1) {
tests_spec_1 = tests_spec_1_1;
}],
execute: function () {
HtmlReporter = function () {
var ResultsNode = function () {
function ResultsNode(result, type, parent) {
this.result = result;
this.type = type;
this.parent = parent;
this.children = [];
}
ResultsNode.prototype.addChild = function (result, type) {
this.children.push(new ResultsNode(result, type, this));
};
ResultsNode.prototype.last = function () {
return this.children[this.children.length - 1];
};
ResultsNode.prototype.updateResult = function (result) {
this.result = result;
};
return ResultsNode;
}();
var ResultsStateBuilder = function () {
function ResultsStateBuilder() {
this.topResults = new ResultsNode({ description: '' }, 'suite', null);
this.currentParent = this.topResults;
this.specsExecuted = 0;
this.failureCount = 0;
this.pendingSpecCount = 0;
}
ResultsStateBuilder.prototype.suiteStarted = function (result) {
this.currentParent.addChild(result, 'suite');
this.currentParent = this.currentParent.last();
};
ResultsStateBuilder.prototype.suiteDone = function (result) {
this.currentParent.updateResult(result);
if (this.currentParent !== this.topResults) {
this.currentParent = this.currentParent.parent;
}
if (result.status === 'failed') {
this.failureCount++;
}
};
ResultsStateBuilder.prototype.specStarted = function (_report) {
};
ResultsStateBuilder.prototype.specDone = function (result) {
this.currentParent.addChild(result, 'spec');
if (result.status !== 'excluded') {
this.specsExecuted++;
}
if (result.status === 'failed') {
this.failureCount++;
}
if (result.status === 'pending') {
this.pendingSpecCount++;
}
};
return ResultsStateBuilder;
}();
var HtmlReporter = function () {
function HtmlReporter(options) {
this.failures = [];
this.deprecationWarnings = [];
this.stateBuilder = new ResultsStateBuilder();
this.config = function () {
return options.env && options.env.configuration() || {};
};
this.getContainer = options.getContainer;
this.createElement = options.createElement;
this.createTextNode = options.createTextNode;
this.navigateWithNewParam = options.navigateWithNewParam || function () {
};
this.addToExistingQueryString = options.addToExistingQueryString || defaultQueryString;
this.filterSpecs = options.filterSpecs;
this.summary = createDom(this, 'div', { className: 'jasmine-summary' });
}
HtmlReporter.prototype.initialize = function () {
clearPrior(this);
this.htmlReporterMain = createDom(this, 'div', { className: 'jasmine_html-reporter' }, createDom(this, 'div', { className: 'jasmine-banner' }, this.createAnchor({
className: 'jasmine-title',
href: 'http://jasmine.github.io/',
target: '_blank'
}), createDom(this, 'span', { className: 'jasmine-version' }, jasmine.version)), createDom(this, 'ul', { className: 'jasmine-symbol-summary' }), createDom(this, 'div', { className: 'jasmine-alert' }), createDom(this, 'div', { className: 'jasmine-results' }, createDom(this, 'div', { className: 'jasmine-failures' })));
this.getContainer().appendChild(this.htmlReporterMain);
};
HtmlReporter.prototype.jasmineStarted = function (options) {
this.totalSpecsDefined = options.totalSpecsDefined || 0;
};
HtmlReporter.prototype.suiteStarted = function (result) {
this.stateBuilder.suiteStarted(result);
};
HtmlReporter.prototype.suiteDone = function (result) {
this.stateBuilder.suiteDone(result);
if (result.status === 'failed') {
this.failures.push(failureDom(result, this));
}
addDeprecationWarnings(result, this);
};
HtmlReporter.prototype.specStarted = function (result) {
this.stateBuilder.specStarted(result);
};
HtmlReporter.prototype.specDone = function (result) {
this.stateBuilder.specDone(result);
if (noExpectations(result)) {
var noSpecMsg = 'Spec "' + result.fullName + '" has no expectations.';
if (result.status === 'failed') {
console.error(noSpecMsg);
} else {
console.warn(noSpecMsg);
}
}
if (!this.symbols) {
this.symbols = find('.jasmine-symbol-summary', this, 'specDone');
}
this.symbols.appendChild(createDom(this, 'li', {
className: this.classNameFromSpecReport(result),
id: 'spec_' + result.id,
title: result.fullName
}));
if (result.status === 'failed') {
this.failures.push(failureDom(result, this));
}
addDeprecationWarnings(result, this);
};
HtmlReporter.prototype.classNameFromSpecReport = function (report) {
return noExpectations(report) && report.status === 'passed' ? 'jasmine-empty' : this.classNameFromStatus(report.status);
};
HtmlReporter.prototype.classNameFromStatus = function (status) {
switch (status) {
case 'excluded':
case 'passed': {
return this.config().hideDisabled ? 'jasmine-excluded-no-display' : 'jasmine-excluded';
}
case 'pending':
return 'jasmine-pending';
case 'failed':
return 'jasmine-failed';
default: {
throw new Error('classNameFromStatus(\'' + status + '\')');
}
}
};
HtmlReporter.prototype.jasmineDone = function (doneResult) {
var _this = this;
var banner = find('.jasmine-banner', this, 'jasmineDone');
var alert = find('.jasmine-alert', this, 'jasmineDone');
var order = doneResult && doneResult.order;
alert.appendChild(createDom(this, 'span', { className: 'jasmine-duration' }, 'finished in ' + doneResult.totalTime / 1000 + 's'));
banner.appendChild(optionsMenu(this.config(), this));
if (this.stateBuilder.specsExecuted < this.totalSpecsDefined) {
var skippedMessage = 'Ran ' + this.stateBuilder.specsExecuted + ' of ' + this.totalSpecsDefined + ' specs - run all';
var skippedLink = this.addToExistingQueryString('spec', '');
alert.appendChild(createDom(this, 'span', { className: 'jasmine-bar jasmine-skipped' }, this.createAnchor({
href: skippedLink,
title: 'Run all specs'
}, skippedMessage)));
}
var statusBarMessage = '';
var statusBarClassName = 'jasmine-overall-result jasmine-bar ';
var globalFailures = doneResult && doneResult.failedExpectations || [];
var failed = this.stateBuilder.failureCount + globalFailures.length > 0;
if (this.totalSpecsDefined > 0 || failed) {
statusBarMessage += pluralize('spec', this.stateBuilder.specsExecuted) + ', ' + pluralize('failure', this.stateBuilder.failureCount);
if (this.stateBuilder.pendingSpecCount) {
statusBarMessage += ', ' + pluralize('pending spec', this.stateBuilder.pendingSpecCount);
}
}
if (doneResult.overallStatus === 'passed') {
statusBarClassName += ' jasmine-passed ';
} else if (doneResult.overallStatus === 'incomplete') {
statusBarClassName += ' jasmine-incomplete ';
statusBarMessage = 'Incomplete: ' + doneResult.incompleteReason + ', ' + statusBarMessage;
} else {
statusBarClassName += ' jasmine-failed ';
}
if (order && order.random) {
var seedBar = createDom(this, 'span', { className: 'jasmine-seed-bar' }, ', randomized with seed ', this.createAnchor({
title: 'randomized with seed ' + order.seed,
href: seedHref(order.seed, this)
}, order.seed));
alert.appendChild(createDom(this, 'span', { className: statusBarClassName }, statusBarMessage, seedBar));
} else {
alert.appendChild(createDom(this, 'span', { className: statusBarClassName }, statusBarMessage));
}
var errorBarClassName = 'jasmine-bar jasmine-errored';
var afterAllMessagePrefix = 'AfterAll ';
var _XZg4P = Date.now();
for (var _i = 0, globalFailures_1 = globalFailures; _i < globalFailures_1.length; _i++) {
if (Date.now() - _XZg4P > 1000) {
throw new Error('Infinite loop suspected after 1000 milliseconds.');
}
{
var globalFailure = globalFailures_1[_i];
alert.appendChild(createDom(this, 'span', { className: errorBarClassName }, globalFailureMessage(globalFailure)));
}
}
function globalFailureMessage(failure) {
if (failure.globalErrorType === 'load') {
var prefix = 'Error during loading: ' + failure.message;
if (failure.filename) {
return prefix + ' in ' + failure.filename + ' line ' + failure.lineno;
} else {
return prefix;
}
} else {
return afterAllMessagePrefix + failure.message;
}
}
addDeprecationWarnings(doneResult, this);
var warningBarClassName = 'jasmine-bar jasmine-warning';
var _b7rM9 = Date.now();
for (var _a = 0, _b = this.deprecationWarnings; _a < _b.length; _a++) {
if (Date.now() - _b7rM9 > 1000) {
throw new Error('Infinite loop suspected after 1000 milliseconds.');
}
{
var deprecationWarning = _b[_a];
alert.appendChild(createDom(this, 'span', { className: warningBarClassName }, 'DEPRECATION: ' + deprecationWarning));
}
}
var results = find('.jasmine-results', this, 'jasmineDone');
results.appendChild(this.summary);
summaryList(this.stateBuilder.topResults, this.summary, this);
if (this.failures.length) {
alert.appendChild(createDom(this, 'span', { className: 'jasmine-menu jasmine-bar jasmine-spec-list' }, createDom(this, 'span', {}, 'Spec List | '), this.createAnchor({
className: 'jasmine-failures-menu',
href: '#'
}, 'Failures')));
alert.appendChild(createDom(this, 'span', { className: 'jasmine-menu jasmine-bar jasmine-failure-list' }, this.createAnchor({
className: 'jasmine-spec-list-menu',
href: '#'
}, 'Spec List'), createDom(this, 'span', {}, ' | Failures ')));
findAnchor('.jasmine-failures-menu', this).onclick = function () {
setMenuModeTo('jasmine-failure-list', _this);
return false;
};
findAnchor('.jasmine-spec-list-menu', this).onclick = function () {
setMenuModeTo('jasmine-spec-list', _this);
return false;
};
setMenuModeTo('jasmine-failure-list', this);
var failureNode = find('.jasmine-failures', this, 'jasmineDone');
var _G4fZb = Date.now();
for (var _c = 0, _d = this.failures; _c < _d.length; _c++) {
if (Date.now() - _G4fZb > 1000) {
throw new Error('Infinite loop suspected after 1000 milliseconds.');
}
{
var failure = _d[_c];
failureNode.appendChild(failure);
}
}
}
};
HtmlReporter.prototype.createAnchor = function (attrs, text) {
var placeholder = {};
if (attrs.className) {
placeholder.className = attrs.className;
}
if (attrs.title) {
placeholder.title = attrs.title;
}
if (attrs.target) {
placeholder.target = attrs.target;
}
if (attrs.href) {
if (attrs.target === '_blank') {
placeholder.href = attrs.href;
}
}
if (typeof text === 'string') {
return createDom(this, 'a', placeholder, text);
} else {
return createDom(this, 'a', placeholder);
}
};
return HtmlReporter;
}();
function failureDom(result, reporter) {
var failure = createDom(reporter, 'div', { className: 'jasmine-spec-detail jasmine-failed' }, failureDescription(result, reporter.stateBuilder.currentParent, reporter), createDom(reporter, 'div', { className: 'jasmine-messages' }));
var messages = failure.childNodes[1];
var _9EsYT = Date.now();
for (var _i = 0, _a = result.failedExpectations; _i < _a.length; _i++) {
if (Date.now() - _9EsYT > 1000) {
throw new Error('Infinite loop suspected after 1000 milliseconds.');
}
{
var expectation = _a[_i];
messages.appendChild(createDom(reporter, 'div', { className: 'jasmine-result-message' }, expectation.message));
messages.appendChild(createDom(reporter, 'div', { className: 'jasmine-stack-trace' }, expectation.stack));
}
}
if (result.failedExpectations.length === 0) {
messages.appendChild(createDom(reporter, 'div', { className: 'jasmine-result-message' }, 'Spec has no expectations'));
}
return failure;
}
function summaryList(resultsTree, domParent, reporter) {
var specListNode;
var _iZpZ3 = Date.now();
for (var _i = 0, _a = resultsTree.children; _i < _a.length; _i++) {
if (Date.now() - _iZpZ3 > 1000) {
throw new Error('Infinite loop suspected after 1000 milliseconds.');
}
{
var resultNode = _a[_i];
if (reporter.filterSpecs && !hasActiveSpec(resultNode)) {
continue;
}
if (resultNode.type === 'suite') {
var result = resultNode.result;
var suiteListNode = createDom(reporter, 'ul', {
className: 'jasmine-suite',
id: 'suite-' + result.id
}, createDom(reporter, 'li', { className: 'jasmine-suite-detail jasmine-' + result.status }, reporter.createAnchor({ href: specHref(result, reporter) }, result.description)));
summaryList(resultNode, suiteListNode, reporter);
domParent.appendChild(suiteListNode);
}
if (resultNode.type === 'spec') {
var result = resultNode.result;
if (domParent.getAttribute('class') !== 'jasmine-specs') {
specListNode = createDom(reporter, 'ul', { className: 'jasmine-specs' });
domParent.appendChild(specListNode);
}
var specDescription = result.description;
if (noExpectations(result)) {
specDescription = 'SPEC HAS NO EXPECTATIONS ' + specDescription;
}
if (result.status === 'pending' && result.pendingReason !== '') {
specDescription = specDescription + ' PENDING WITH MESSAGE: ' + result.pendingReason;
}
specListNode.appendChild(createDom(reporter, 'li', {
className: 'jasmine-' + result.status,
id: 'spec-' + result.id
}, reporter.createAnchor({ href: specHref(result, reporter) }, specDescription)));
}
}
}
}
function optionsMenu(config, reporter) {
var optionsMenuDom = createDom(reporter, 'div', { className: 'jasmine-run-options' }, createDom(reporter, 'span', { className: 'jasmine-trigger' }, 'Options'), createDom(reporter, 'div', { className: 'jasmine-payload' }, createDom(reporter, 'div', { className: 'jasmine-stop-on-failure' }, createDom(reporter, 'input', {
className: 'jasmine-fail-fast',
id: 'jasmine-fail-fast',
type: 'checkbox'
}), createDom(reporter, 'label', {
className: 'jasmine-label',
for: 'jasmine-fail-fast'
}, 'stop execution on spec failure')), createDom(reporter, 'div', { className: 'jasmine-throw-failures' }, createDom(reporter, 'input', {
className: 'jasmine-throw',
id: 'jasmine-throw-failures',
type: 'checkbox'
}), createDom(reporter, 'label', {
className: 'jasmine-label',
for: 'jasmine-throw-failures'
}, 'stop spec on expectation failure')), createDom(reporter, 'div', { className: 'jasmine-random-order' }, createDom(reporter, 'input', {
className: 'jasmine-random',
id: 'jasmine-random-order',
type: 'checkbox'
}), createDom(reporter, 'label', {
className: 'jasmine-label',
for: 'jasmine-random-order'
}, 'run tests in random order')), createDom(reporter, 'div', { className: 'jasmine-hide-disabled' }, createDom(reporter, 'input', {
className: 'jasmine-disabled',
id: 'jasmine-hide-disabled',
type: 'checkbox'
}), createDom(reporter, 'label', {
className: 'jasmine-label',
for: 'jasmine-hide-disabled'
}, 'hide disabled tests'))));
var failFastCheckbox = optionsMenuDom.querySelector('#jasmine-fail-fast');
failFastCheckbox.checked = config.failFast ? true : false;
failFastCheckbox.onclick = function () {
reporter.navigateWithNewParam('failFast', !config.failFast);
};
var throwCheckbox = optionsMenuDom.querySelector('#jasmine-throw-failures');
throwCheckbox.checked = config.oneFailurePerSpec ? true : false;
throwCheckbox.onclick = function () {
reporter.navigateWithNewParam('throwFailures', !config.oneFailurePerSpec);
};
var randomCheckbox = optionsMenuDom.querySelector('#jasmine-random-order');
randomCheckbox.checked = config.random ? true : false;
randomCheckbox.onclick = function () {
reporter.navigateWithNewParam('random', !config.random);
};
var hideDisabled = optionsMenuDom.querySelector('#jasmine-hide-disabled');
hideDisabled.checked = config.hideDisabled ? true : false;
hideDisabled.onclick = function () {
reporter.navigateWithNewParam('hideDisabled', !config.hideDisabled);
};
var optionsTrigger = optionsMenuDom.querySelector('.jasmine-trigger');
var optionsPayload = optionsMenuDom.querySelector('.jasmine-payload');
var isOpen = /\bjasmine-open\b/;
optionsTrigger.onclick = function () {
if (isOpen.test(optionsPayload.className)) {
optionsPayload.className = optionsPayload.className.replace(isOpen, '');
} else {
optionsPayload.className += ' jasmine-open';
}
};
return optionsMenuDom;
}
function failureDescription(result, suite, reporter) {
var wrapper = createDom(reporter, 'div', { className: 'jasmine-description' }, reporter.createAnchor({
title: result.description,
href: specHref(result, reporter)
}, result.description));
var suiteLink;
var _gsnNQ = Date.now();
while (suite && suite.parent) {
if (Date.now() - _gsnNQ > 1000) {
throw new Error('Infinite loop suspected after 1000 milliseconds.');
}
{
wrapper.insertBefore(reporter.createTextNode(' > '), wrapper.firstChild);
suiteLink = reporter.createAnchor({ href: suiteHref(suite, reporter) }, suite.result.description);
wrapper.insertBefore(suiteLink, wrapper.firstChild);
suite = suite.parent;
}
}
return wrapper;
}
function suiteHref(suite, reporter) {
var els = [];
var _L3QlQ = Date.now();
while (suite && suite.parent) {
if (Date.now() - _L3QlQ > 1000) {
throw new Error('Infinite loop suspected after 1000 milliseconds.');
}
{
els.unshift(suite.result.description);
suite = suite.parent;
}
}
return reporter.addToExistingQueryString('spec', els.join(' '));
}
function addDeprecationWarnings(result, reporter) {
if (result && result.deprecationWarnings) {
var _VUSSS = Date.now();
for (var _i = 0, _a = result.deprecationWarnings; _i < _a.length; _i++) {
if (Date.now() - _VUSSS > 1000) {
throw new Error('Infinite loop suspected after 1000 milliseconds.');
}
{
var deprecationWarning = _a[_i];
var warning = deprecationWarning.message;
reporter.deprecationWarnings.push(warning);
}
}
}
}
function findAnchor(selector, reporter) {
var element = find(selector, reporter, 'findAnchor');
if (element instanceof HTMLAnchorElement) {
return element;
} else {
throw new Error(selector + ' is not an HTMLAnchorElement');
}
}
function find(selector, reporter, _origin) {
var selectors = '.jasmine_html-reporter ' + selector;
var element = reporter.getContainer().querySelector(selectors);
if (element) {
return element;
} else {
throw new Error('Unable to find selectors ' + JSON.stringify(selectors));
}
}
function clearPrior(reporter) {
try {
var oldReporter = find('', reporter, 'clearPrior');
reporter.getContainer().removeChild(oldReporter);
} catch (e) {
}
}
function createDom(factory, type, attrs) {
var _children = [];
var _TZGd9 = Date.now();
for (var _i = 3; _i < arguments.length; _i++) {
if (Date.now() - _TZGd9 > 1000) {
throw new Error('Infinite loop suspected after 1000 milliseconds.');
}
{
_children[_i - 3] = arguments[_i];
}
}
var el = factory.createElement(type);
var _6Hbhe = Date.now();
for (var i = 3; i < arguments.length; i++) {
if (Date.now() - _6Hbhe > 1000) {
throw new Error('Infinite loop suspected after 1000 milliseconds.');
}
{
var child = arguments[i];
if (typeof child === 'string') {
el.appendChild(factory.createTextNode(child));
} else {
if (child) {
el.appendChild(child);
}
}
}
}
for (var attr in attrs) {
if (attr === 'className') {
el[attr] = attrs[attr];
} else {
el.setAttribute(attr, attrs[attr]);
}
}
return el;
}
function pluralize(singular, count) {
var word = count === 1 ? singular : singular + 's';
return '' + count + ' ' + word;
}
function specHref(result, reporter) {
return reporter.addToExistingQueryString('spec', result.fullName);
}
function seedHref(seed, reporter) {
return reporter.addToExistingQueryString('seed', seed);
}
function defaultQueryString(key, value) {
return '?' + key + '=' + value;
}
function setMenuModeTo(mode, reporter) {
reporter.htmlReporterMain.setAttribute('class', 'jasmine_html-reporter ' + mode);
}
function noExpectations(result) {
var allExpectations = result.failedExpectations.length + result.passedExpectations.length;
return allExpectations === 0 && (result.status === 'passed' || result.status === 'failed');
}
function hasActiveSpec(resultNode) {
if (resultNode.type === 'spec') {
var result = resultNode.result;
if (result.status !== 'excluded') {
return true;
}
}
if (resultNode.type === 'suite') {
var j = resultNode.children.length;
var _6HHpq = Date.now();
for (var i = 0; i < j; i++) {
if (Date.now() - _6HHpq > 1000) {
throw new Error('Infinite loop suspected after 1000 milliseconds.');
}
{
if (hasActiveSpec(resultNode.children[i])) {
return true;
}
}
}
}
return false;
}
return HtmlReporter;
}();
config = {
random: false,
failFast: false,
failSpecWithNoExpectations: false,
oneFailurePerSpec: false,
hideDisabled: false,
specFilter: void 0,
promise: void 0
};
specifications = [];
DomReady.ready(runTests).catch(function (e) {
return console.error(e);
});
}
};
});
</script>
<script>
System.import('./index.js')
</script>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<base href="/">
<style>
body { background-color: #eeeeee; }
</style>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jasmine/3.4.0/jasmine.css">
<script src="https://www.stemcstudio.com:/vendor/[email protected]/domready.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/3.4.0/jasmine.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/3.4.0/jasmine-html.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/stats.js/r16/Stats.min.js"></script>
<script src="https://unpkg.com/[email protected]/dist/system.js"></script>
</head>
<body>
<script>
System.config({
"warnings": false,
"map": {
"davinci-eight": "https://unpkg.com/[email protected]/build/browser/index.js"
}
});
</script>
<script>
System.register('./Example.spec.js', [], function (exports_1, context_1) {
'use strict';
var __moduleName = context_1 && context_1.id;
function default_1() {
describe('...', function () {
it('should ...', function () {
expect(true).toBeTruthy();
});
});
}
exports_1('default', default_1);
return {
setters: [],
execute: function () {
}
};
});
System.register('./index.js', ['davinci-eight'], function (exports_1, context_1) {
'use strict';
var EIGHT, engine, scene, ambients, camera, dirLight, trackball, body, stats, animate;
var __moduleName = context_1 && context_1.id;
return {
setters: [function (EIGHT_1) {
EIGHT = EIGHT_1;
}],
execute: function () {
engine = new EIGHT.Engine('canvas').size(500, 500).clearColor(0.1, 0.1, 0.1, 1).enable(EIGHT.Capability.DEPTH_TEST);
scene = new EIGHT.Scene(engine);
ambients = [];
camera = new EIGHT.PerspectiveCamera();
camera.eye.scale(5);
ambients.push(camera);
dirLight = new EIGHT.DirectionalLight();
ambients.push(dirLight);
trackball = new EIGHT.TrackballControls(camera, window);
trackball.subscribe(engine.canvas);
trackball.noPan = true;
body = new EIGHT.Box(engine, { color: EIGHT.Color.blueviolet });
scene.add(body);
stats = new Stats();
document.body.appendChild(stats.domElement);
animate = function (_timestamp) {
stats.begin();
engine.clear();
trackball.update();
dirLight.direction.copy(camera.look).sub(camera.eye);
scene.render(ambients);
stats.end();
requestAnimationFrame(animate);
};
requestAnimationFrame(animate);
}
};
});
System.register('./tests.spec.js', [], function (exports_1, context_1) {
'use strict';
var __moduleName = context_1 && context_1.id;
function spec() {
describe('example', function () {
it('should pass', function () {
expect(true).toBeTruthy();
});
});
}
exports_1('spec', spec);
return {
setters: [],
execute: function () {
}
};
});
System.register('./tests.js', ['./tests.spec.js'], function (exports_1, context_1) {
'use strict';
var tests_spec_1, HtmlReporter, config, specifications;
var __moduleName = context_1 && context_1.id;
function getContainer() {
var element = document.body;
return element;
}
function onChangeOption(key, value) {
switch (key) {
case 'failFast': {
config.failFast = !config.failFast;
break;
}
case 'throwFailures': {
config.oneFailurePerSpec = !config.oneFailurePerSpec;
break;
}
case 'random': {
config.random = !config.random;
break;
}
case 'hideDisabled': {
config.hideDisabled = !config.hideDisabled;
break;
}
default: {
console.warn('navigateWithNewParam(key=' + key + ', value=' + JSON.stringify(value));
}
}
runTests();
}
function addSpec(value) {
specifications.push(value);
return '';
}
function addSeed(_seed) {
return '';
}
function runTests() {
var jasmineCore = jasmineRequire.core(jasmineRequire);
jasmineRequire.html(jasmineCore);
var env = jasmineCore.getEnv();
var jasmineInterface = jasmineRequire.interface(jasmineCore, env);
extend(window, jasmineInterface);
var htmlReporter = new HtmlReporter({
env: env,
addToExistingQueryString: function (key, value) {
switch (key) {
case 'spec': {
return addSpec(value);
break;
}
case 'seed': {
return addSeed(parseInt(value, 10));
break;
}
default: {
throw new Error('Unknown key: ' + key);
}
}
},
navigateWithNewParam: onChangeOption,
getContainer: getContainer,
createElement: function () {
return document.createElement.apply(document, arguments);
},
createTextNode: function () {
return document.createTextNode.apply(document, arguments);
},
timer: new jasmine.Timer(),
filterSpecs: true
});
env.addReporter(jasmineInterface.jsApiReporter);
env.addReporter(htmlReporter);
env.configure(config);
htmlReporter.initialize();
describe('spec', tests_spec_1.spec);
env.execute();
}
function extend(destination, source) {
for (var property in source) {
if (source.hasOwnProperty(property)) {
destination[property] = source[property];
}
}
return destination;
}
return {
setters: [function (tests_spec_1_1) {
tests_spec_1 = tests_spec_1_1;
}],
execute: function () {
HtmlReporter = function () {
var ResultsNode = function () {
function ResultsNode(result, type, parent) {
this.result = result;
this.type = type;
this.parent = parent;
this.children = [];
}
ResultsNode.prototype.addChild = function (result, type) {
this.children.push(new ResultsNode(result, type, this));
};
ResultsNode.prototype.last = function () {
return this.children[this.children.length - 1];
};
ResultsNode.prototype.updateResult = function (result) {
this.result = result;
};
return ResultsNode;
}();
var ResultsStateBuilder = function () {
function ResultsStateBuilder() {
this.topResults = new ResultsNode({ description: '' }, 'suite', null);
this.currentParent = this.topResults;
this.specsExecuted = 0;
this.failureCount = 0;
this.pendingSpecCount = 0;
}
ResultsStateBuilder.prototype.suiteStarted = function (result) {
this.currentParent.addChild(result, 'suite');
this.currentParent = this.currentParent.last();
};
ResultsStateBuilder.prototype.suiteDone = function (result) {
this.currentParent.updateResult(result);
if (this.currentParent !== this.topResults) {
this.currentParent = this.currentParent.parent;
}
if (result.status === 'failed') {
this.failureCount++;
}
};
ResultsStateBuilder.prototype.specStarted = function (_report) {
};
ResultsStateBuilder.prototype.specDone = function (result) {
this.currentParent.addChild(result, 'spec');
if (result.status !== 'excluded') {
this.specsExecuted++;
}
if (result.status === 'failed') {
this.failureCount++;
}
if (result.status === 'pending') {
this.pendingSpecCount++;
}
};
return ResultsStateBuilder;
}();
var HtmlReporter = function () {
function HtmlReporter(options) {
this.failures = [];
this.deprecationWarnings = [];
this.stateBuilder = new ResultsStateBuilder();
this.config = function () {
return options.env && options.env.configuration() || {};
};
this.getContainer = options.getContainer;
this.createElement = options.createElement;
this.createTextNode = options.createTextNode;
this.navigateWithNewParam = options.navigateWithNewParam || function () {
};
this.addToExistingQueryString = options.addToExistingQueryString || defaultQueryString;
this.filterSpecs = options.filterSpecs;
this.summary = createDom(this, 'div', { className: 'jasmine-summary' });
}
HtmlReporter.prototype.initialize = function () {
clearPrior(this);
this.htmlReporterMain = createDom(this, 'div', { className: 'jasmine_html-reporter' }, createDom(this, 'div', { className: 'jasmine-banner' }, this.createAnchor({
className: 'jasmine-title',
href: 'http://jasmine.github.io/',
target: '_blank'
}), createDom(this, 'span', { className: 'jasmine-version' }, jasmine.version)), createDom(this, 'ul', { className: 'jasmine-symbol-summary' }), createDom(this, 'div', { className: 'jasmine-alert' }), createDom(this, 'div', { className: 'jasmine-results' }, createDom(this, 'div', { className: 'jasmine-failures' })));
this.getContainer().appendChild(this.htmlReporterMain);
};
HtmlReporter.prototype.jasmineStarted = function (options) {
this.totalSpecsDefined = options.totalSpecsDefined || 0;
};
HtmlReporter.prototype.suiteStarted = function (result) {
this.stateBuilder.suiteStarted(result);
};
HtmlReporter.prototype.suiteDone = function (result) {
this.stateBuilder.suiteDone(result);
if (result.status === 'failed') {
this.failures.push(failureDom(result, this));
}
addDeprecationWarnings(result, this);
};
HtmlReporter.prototype.specStarted = function (result) {
this.stateBuilder.specStarted(result);
};
HtmlReporter.prototype.specDone = function (result) {
this.stateBuilder.specDone(result);
if (noExpectations(result)) {
var noSpecMsg = 'Spec "' + result.fullName + '" has no expectations.';
if (result.status === 'failed') {
console.error(noSpecMsg);
} else {
console.warn(noSpecMsg);
}
}
if (!this.symbols) {
this.symbols = find('.jasmine-symbol-summary', this, 'specDone');
}
this.symbols.appendChild(createDom(this, 'li', {
className: this.classNameFromSpecReport(result),
id: 'spec_' + result.id,
title: result.fullName
}));
if (result.status === 'failed') {
this.failures.push(failureDom(result, this));
}
addDeprecationWarnings(result, this);
};
HtmlReporter.prototype.classNameFromSpecReport = function (report) {
return noExpectations(report) && report.status === 'passed' ? 'jasmine-empty' : this.classNameFromStatus(report.status);
};
HtmlReporter.prototype.classNameFromStatus = function (status) {
switch (status) {
case 'excluded':
case 'passed': {
return this.config().hideDisabled ? 'jasmine-excluded-no-display' : 'jasmine-excluded';
}
case 'pending':
return 'jasmine-pending';
case 'failed':
return 'jasmine-failed';
default: {
throw new Error('classNameFromStatus(\'' + status + '\')');
}
}
};
HtmlReporter.prototype.jasmineDone = function (doneResult) {
var _this = this;
var banner = find('.jasmine-banner', this, 'jasmineDone');
var alert = find('.jasmine-alert', this, 'jasmineDone');
var order = doneResult && doneResult.order;
alert.appendChild(createDom(this, 'span', { className: 'jasmine-duration' }, 'finished in ' + doneResult.totalTime / 1000 + 's'));
banner.appendChild(optionsMenu(this.config(), this));
if (this.stateBuilder.specsExecuted < this.totalSpecsDefined) {
var skippedMessage = 'Ran ' + this.stateBuilder.specsExecuted + ' of ' + this.totalSpecsDefined + ' specs - run all';
var skippedLink = this.addToExistingQueryString('spec', '');
alert.appendChild(createDom(this, 'span', { className: 'jasmine-bar jasmine-skipped' }, this.createAnchor({
href: skippedLink,
title: 'Run all specs'
}, skippedMessage)));
}
var statusBarMessage = '';
var statusBarClassName = 'jasmine-overall-result jasmine-bar ';
var globalFailures = doneResult && doneResult.failedExpectations || [];
var failed = this.stateBuilder.failureCount + globalFailures.length > 0;
if (this.totalSpecsDefined > 0 || failed) {
statusBarMessage += pluralize('spec', this.stateBuilder.specsExecuted) + ', ' + pluralize('failure', this.stateBuilder.failureCount);
if (this.stateBuilder.pendingSpecCount) {
statusBarMessage += ', ' + pluralize('pending spec', this.stateBuilder.pendingSpecCount);
}
}
if (doneResult.overallStatus === 'passed') {
statusBarClassName += ' jasmine-passed ';
} else if (doneResult.overallStatus === 'incomplete') {
statusBarClassName += ' jasmine-incomplete ';
statusBarMessage = 'Incomplete: ' + doneResult.incompleteReason + ', ' + statusBarMessage;
} else {
statusBarClassName += ' jasmine-failed ';
}
if (order && order.random) {
var seedBar = createDom(this, 'span', { className: 'jasmine-seed-bar' }, ', randomized with seed ', this.createAnchor({
title: 'randomized with seed ' + order.seed,
href: seedHref(order.seed, this)
}, order.seed));
alert.appendChild(createDom(this, 'span', { className: statusBarClassName }, statusBarMessage, seedBar));
} else {
alert.appendChild(createDom(this, 'span', { className: statusBarClassName }, statusBarMessage));
}
var errorBarClassName = 'jasmine-bar jasmine-errored';
var afterAllMessagePrefix = 'AfterAll ';
var _uyfwQ = Date.now();
for (var _i = 0, globalFailures_1 = globalFailures; _i < globalFailures_1.length; _i++) {
if (Date.now() - _uyfwQ > 1000) {
throw new Error('Infinite loop suspected after 1000 milliseconds.');
}
{
var globalFailure = globalFailures_1[_i];
alert.appendChild(createDom(this, 'span', { className: errorBarClassName }, globalFailureMessage(globalFailure)));
}
}
function globalFailureMessage(failure) {
if (failure.globalErrorType === 'load') {
var prefix = 'Error during loading: ' + failure.message;
if (failure.filename) {
return prefix + ' in ' + failure.filename + ' line ' + failure.lineno;
} else {
return prefix;
}
} else {
return afterAllMessagePrefix + failure.message;
}
}
addDeprecationWarnings(doneResult, this);
var warningBarClassName = 'jasmine-bar jasmine-warning';
var _CpZYT = Date.now();
for (var _a = 0, _b = this.deprecationWarnings; _a < _b.length; _a++) {
if (Date.now() - _CpZYT > 1000) {
throw new Error('Infinite loop suspected after 1000 milliseconds.');
}
{
var deprecationWarning = _b[_a];
alert.appendChild(createDom(this, 'span', { className: warningBarClassName }, 'DEPRECATION: ' + deprecationWarning));
}
}
var results = find('.jasmine-results', this, 'jasmineDone');
results.appendChild(this.summary);
summaryList(this.stateBuilder.topResults, this.summary, this);
if (this.failures.length) {
alert.appendChild(createDom(this, 'span', { className: 'jasmine-menu jasmine-bar jasmine-spec-list' }, createDom(this, 'span', {}, 'Spec List | '), this.createAnchor({
className: 'jasmine-failures-menu',
href: '#'
}, 'Failures')));
alert.appendChild(createDom(this, 'span', { className: 'jasmine-menu jasmine-bar jasmine-failure-list' }, this.createAnchor({
className: 'jasmine-spec-list-menu',
href: '#'
}, 'Spec List'), createDom(this, 'span', {}, ' | Failures ')));
findAnchor('.jasmine-failures-menu', this).onclick = function () {
setMenuModeTo('jasmine-failure-list', _this);
return false;
};
findAnchor('.jasmine-spec-list-menu', this).onclick = function () {
setMenuModeTo('jasmine-spec-list', _this);
return false;
};
setMenuModeTo('jasmine-failure-list', this);
var failureNode = find('.jasmine-failures', this, 'jasmineDone');
var _9gtYg = Date.now();
for (var _c = 0, _d = this.failures; _c < _d.length; _c++) {
if (Date.now() - _9gtYg > 1000) {
throw new Error('Infinite loop suspected after 1000 milliseconds.');
}
{
var failure = _d[_c];
failureNode.appendChild(failure);
}
}
}
};
HtmlReporter.prototype.createAnchor = function (attrs, text) {
var placeholder = {};
if (attrs.className) {
placeholder.className = attrs.className;
}
if (attrs.title) {
placeholder.title = attrs.title;
}
if (attrs.target) {
placeholder.target = attrs.target;
}
if (attrs.href) {
if (attrs.target === '_blank') {
placeholder.href = attrs.href;
}
}
if (typeof text === 'string') {
return createDom(this, 'a', placeholder, text);
} else {
return createDom(this, 'a', placeholder);
}
};
return HtmlReporter;
}();
function failureDom(result, reporter) {
var failure = createDom(reporter, 'div', { className: 'jasmine-spec-detail jasmine-failed' }, failureDescription(result, reporter.stateBuilder.currentParent, reporter), createDom(reporter, 'div', { className: 'jasmine-messages' }));
var messages = failure.childNodes[1];
var _VfSAe = Date.now();
for (var _i = 0, _a = result.failedExpectations; _i < _a.length; _i++) {
if (Date.now() - _VfSAe > 1000) {
throw new Error('Infinite loop suspected after 1000 milliseconds.');
}
{
var expectation = _a[_i];
messages.appendChild(createDom(reporter, 'div', { className: 'jasmine-result-message' }, expectation.message));
messages.appendChild(createDom(reporter, 'div', { className: 'jasmine-stack-trace' }, expectation.stack));
}
}
if (result.failedExpectations.length === 0) {
messages.appendChild(createDom(reporter, 'div', { className: 'jasmine-result-message' }, 'Spec has no expectations'));
}
return failure;
}
function summaryList(resultsTree, domParent, reporter) {
var specListNode;
var _m4Li7 = Date.now();
for (var _i = 0, _a = resultsTree.children; _i < _a.length; _i++) {
if (Date.now() - _m4Li7 > 1000) {
throw new Error('Infinite loop suspected after 1000 milliseconds.');
}
{
var resultNode = _a[_i];
if (reporter.filterSpecs && !hasActiveSpec(resultNode)) {
continue;
}
if (resultNode.type === 'suite') {
var result = resultNode.result;
var suiteListNode = createDom(reporter, 'ul', {
className: 'jasmine-suite',
id: 'suite-' + result.id
}, createDom(reporter, 'li', { className: 'jasmine-suite-detail jasmine-' + result.status }, reporter.createAnchor({ href: specHref(result, reporter) }, result.description)));
summaryList(resultNode, suiteListNode, reporter);
domParent.appendChild(suiteListNode);
}
if (resultNode.type === 'spec') {
var result = resultNode.result;
if (domParent.getAttribute('class') !== 'jasmine-specs') {
specListNode = createDom(reporter, 'ul', { className: 'jasmine-specs' });
domParent.appendChild(specListNode);
}
var specDescription = result.description;
if (noExpectations(result)) {
specDescription = 'SPEC HAS NO EXPECTATIONS ' + specDescription;
}
if (result.status === 'pending' && result.pendingReason !== '') {
specDescription = specDescription + ' PENDING WITH MESSAGE: ' + result.pendingReason;
}
specListNode.appendChild(createDom(reporter, 'li', {
className: 'jasmine-' + result.status,
id: 'spec-' + result.id
}, reporter.createAnchor({ href: specHref(result, reporter) }, specDescription)));
}
}
}
}
function optionsMenu(config, reporter) {
var optionsMenuDom = createDom(reporter, 'div', { className: 'jasmine-run-options' }, createDom(reporter, 'span', { className: 'jasmine-trigger' }, 'Options'), createDom(reporter, 'div', { className: 'jasmine-payload' }, createDom(reporter, 'div', { className: 'jasmine-stop-on-failure' }, createDom(reporter, 'input', {
className: 'jasmine-fail-fast',
id: 'jasmine-fail-fast',
type: 'checkbox'
}), createDom(reporter, 'label', {
className: 'jasmine-label',
for: 'jasmine-fail-fast'
}, 'stop execution on spec failure')), createDom(reporter, 'div', { className: 'jasmine-throw-failures' }, createDom(reporter, 'input', {
className: 'jasmine-throw',
id: 'jasmine-throw-failures',
type: 'checkbox'
}), createDom(reporter, 'label', {
className: 'jasmine-label',
for: 'jasmine-throw-failures'
}, 'stop spec on expectation failure')), createDom(reporter, 'div', { className: 'jasmine-random-order' }, createDom(reporter, 'input', {
className: 'jasmine-random',
id: 'jasmine-random-order',
type: 'checkbox'
}), createDom(reporter, 'label', {
className: 'jasmine-label',
for: 'jasmine-random-order'
}, 'run tests in random order')), createDom(reporter, 'div', { className: 'jasmine-hide-disabled' }, createDom(reporter, 'input', {
className: 'jasmine-disabled',
id: 'jasmine-hide-disabled',
type: 'checkbox'
}), createDom(reporter, 'label', {
className: 'jasmine-label',
for: 'jasmine-hide-disabled'
}, 'hide disabled tests'))));
var failFastCheckbox = optionsMenuDom.querySelector('#jasmine-fail-fast');
failFastCheckbox.checked = config.failFast ? true : false;
failFastCheckbox.onclick = function () {
reporter.navigateWithNewParam('failFast', !config.failFast);
};
var throwCheckbox = optionsMenuDom.querySelector('#jasmine-throw-failures');
throwCheckbox.checked = config.oneFailurePerSpec ? true : false;
throwCheckbox.onclick = function () {
reporter.navigateWithNewParam('throwFailures', !config.oneFailurePerSpec);
};
var randomCheckbox = optionsMenuDom.querySelector('#jasmine-random-order');
randomCheckbox.checked = config.random ? true : false;
randomCheckbox.onclick = function () {
reporter.navigateWithNewParam('random', !config.random);
};
var hideDisabled = optionsMenuDom.querySelector('#jasmine-hide-disabled');
hideDisabled.checked = config.hideDisabled ? true : false;
hideDisabled.onclick = function () {
reporter.navigateWithNewParam('hideDisabled', !config.hideDisabled);
};
var optionsTrigger = optionsMenuDom.querySelector('.jasmine-trigger');
var optionsPayload = optionsMenuDom.querySelector('.jasmine-payload');
var isOpen = /\bjasmine-open\b/;
optionsTrigger.onclick = function () {
if (isOpen.test(optionsPayload.className)) {
optionsPayload.className = optionsPayload.className.replace(isOpen, '');
} else {
optionsPayload.className += ' jasmine-open';
}
};
return optionsMenuDom;
}
function failureDescription(result, suite, reporter) {
var wrapper = createDom(reporter, 'div', { className: 'jasmine-description' }, reporter.createAnchor({
title: result.description,
href: specHref(result, reporter)
}, result.description));
var suiteLink;
var _zWG30 = Date.now();
while (suite && suite.parent) {
if (Date.now() - _zWG30 > 1000) {
throw new Error('Infinite loop suspected after 1000 milliseconds.');
}
{
wrapper.insertBefore(reporter.createTextNode(' > '), wrapper.firstChild);
suiteLink = reporter.createAnchor({ href: suiteHref(suite, reporter) }, suite.result.description);
wrapper.insertBefore(suiteLink, wrapper.firstChild);
suite = suite.parent;
}
}
return wrapper;
}
function suiteHref(suite, reporter) {
var els = [];
var _6xReF = Date.now();
while (suite && suite.parent) {
if (Date.now() - _6xReF > 1000) {
throw new Error('Infinite loop suspected after 1000 milliseconds.');
}
{
els.unshift(suite.result.description);
suite = suite.parent;
}
}
return reporter.addToExistingQueryString('spec', els.join(' '));
}
function addDeprecationWarnings(result, reporter) {
if (result && result.deprecationWarnings) {
var _VMn04 = Date.now();
for (var _i = 0, _a = result.deprecationWarnings; _i < _a.length; _i++) {
if (Date.now() - _VMn04 > 1000) {
throw new Error('Infinite loop suspected after 1000 milliseconds.');
}
{
var deprecationWarning = _a[_i];
var warning = deprecationWarning.message;
reporter.deprecationWarnings.push(warning);
}
}
}
}
function findAnchor(selector, reporter) {
var element = find(selector, reporter, 'findAnchor');
if (element instanceof HTMLAnchorElement) {
return element;
} else {
throw new Error(selector + ' is not an HTMLAnchorElement');
}
}
function find(selector, reporter, _origin) {
var selectors = '.jasmine_html-reporter ' + selector;
var element = reporter.getContainer().querySelector(selectors);
if (element) {
return element;
} else {
throw new Error('Unable to find selectors ' + JSON.stringify(selectors));
}
}
function clearPrior(reporter) {
try {
var oldReporter = find('', reporter, 'clearPrior');
reporter.getContainer().removeChild(oldReporter);
} catch (e) {
}
}
function createDom(factory, type, attrs) {
var _children = [];
var _MtJb0 = Date.now();
for (var _i = 3; _i < arguments.length; _i++) {
if (Date.now() - _MtJb0 > 1000) {
throw new Error('Infinite loop suspected after 1000 milliseconds.');
}
{
_children[_i - 3] = arguments[_i];
}
}
var el = factory.createElement(type);
var _j6skF = Date.now();
for (var i = 3; i < arguments.length; i++) {
if (Date.now() - _j6skF > 1000) {
throw new Error('Infinite loop suspected after 1000 milliseconds.');
}
{
var child = arguments[i];
if (typeof child === 'string') {
el.appendChild(factory.createTextNode(child));
} else {
if (child) {
el.appendChild(child);
}
}
}
}
for (var attr in attrs) {
if (attr === 'className') {
el[attr] = attrs[attr];
} else {
el.setAttribute(attr, attrs[attr]);
}
}
return el;
}
function pluralize(singular, count) {
var word = count === 1 ? singular : singular + 's';
return '' + count + ' ' + word;
}
function specHref(result, reporter) {
return reporter.addToExistingQueryString('spec', result.fullName);
}
function seedHref(seed, reporter) {
return reporter.addToExistingQueryString('seed', seed);
}
function defaultQueryString(key, value) {
return '?' + key + '=' + value;
}
function setMenuModeTo(mode, reporter) {
reporter.htmlReporterMain.setAttribute('class', 'jasmine_html-reporter ' + mode);
}
function noExpectations(result) {
var allExpectations = result.failedExpectations.length + result.passedExpectations.length;
return allExpectations === 0 && (result.status === 'passed' || result.status === 'failed');
}
function hasActiveSpec(resultNode) {
if (resultNode.type === 'spec') {
var result = resultNode.result;
if (result.status !== 'excluded') {
return true;
}
}
if (resultNode.type === 'suite') {
var j = resultNode.children.length;
var _iuj2Q = Date.now();
for (var i = 0; i < j; i++) {
if (Date.now() - _iuj2Q > 1000) {
throw new Error('Infinite loop suspected after 1000 milliseconds.');
}
{
if (hasActiveSpec(resultNode.children[i])) {
return true;
}
}
}
}
return false;
}
return HtmlReporter;
}();
config = {
random: false,
failFast: false,
failSpecWithNoExpectations: false,
oneFailurePerSpec: false,
hideDisabled: false,
specFilter: void 0,
promise: void 0
};
specifications = [];
DomReady.ready(runTests).catch(function (e) {
return console.error(e);
});
}
};
});
</script>
<script>
System.defaultJSExtensions = true
System.import('./tests.js').catch(function(e) { console.error(e) })
</script>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" type="text/css" href="https://thimble.mozilla.org/tutorial/tutorial.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jasmine/3.4.0/jasmine.css">
<script src="https://www.stemcstudio.com:/vendor/[email protected]/domready.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/3.4.0/jasmine.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/3.4.0/jasmine-html.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/stats.js/r16/Stats.min.js"></script>
<script src="https://unpkg.com/[email protected]/dist/system.js"></script>
</head>
<body>
<script>
System.config({
"warnings": false,
"map": {
"davinci-eight": "https://unpkg.com/[email protected]/build/browser/index.js"
}
});
</script>
<div class="tutorial">
<h1>STEMCstudio Tutorial</h1>
<p>
Edit this tutorial to provide step-by-step instructions to people remixing your project, including those who might be doing it on their own (without a mentor/facilitator/teacher). They will be able to toggle between the Preview pane and this Tutorial. Replace this section with an overview or some background about your project.
</p>
<p>
Check out the <a href="https://thimble.mozilla.org/tutorial/tutorial-style-guide.html" target="_blank">style guide</a> for HTML elements you can include.
</p>
<h3>Step-by-Step Instructions</h3>
<ol class="steps">
<li>
Add your first step here.
</li>
<li>
Add your second step here.
</li>
<li>
Add your third step here, and add more steps if needed.
</li>
<li>
Add a note of congratulations for completing the project and remixing the Web! Note any specific instructions for where to share the completed project if appropriate (e.g. Twitter hashtag, email to teacher, etc.)
</li>
</ol>
<pre class="code"> const x = 27;
export default function(x: number, y: number) {
const that = {
};
return that;
}
</pre>
</div>
<script>
System.register('./Example.spec.js', [], function (exports_1, context_1) {
'use strict';
var __moduleName = context_1 && context_1.id;
function default_1() {
describe('...', function () {
it('should ...', function () {
expect(true).toBeTruthy();
});
});
}
exports_1('default', default_1);
return {
setters: [],
execute: function () {
}
};
});
System.register('./index.js', ['davinci-eight'], function (exports_1, context_1) {
'use strict';
var EIGHT, engine, scene, ambients, camera, dirLight, trackball, body, stats, animate;
var __moduleName = context_1 && context_1.id;
return {
setters: [function (EIGHT_1) {
EIGHT = EIGHT_1;
}],
execute: function () {
engine = new EIGHT.Engine('canvas').size(500, 500).clearColor(0.1, 0.1, 0.1, 1).enable(EIGHT.Capability.DEPTH_TEST);
scene = new EIGHT.Scene(engine);
ambients = [];
camera = new EIGHT.PerspectiveCamera();
camera.eye.scale(5);
ambients.push(camera);
dirLight = new EIGHT.DirectionalLight();
ambients.push(dirLight);
trackball = new EIGHT.TrackballControls(camera, window);
trackball.subscribe(engine.canvas);
trackball.noPan = true;
body = new EIGHT.Box(engine, { color: EIGHT.Color.blueviolet });
scene.add(body);
stats = new Stats();
document.body.appendChild(stats.domElement);
animate = function (_timestamp) {
stats.begin();
engine.clear();
trackball.update();
dirLight.direction.copy(camera.look).sub(camera.eye);
scene.render(ambients);
stats.end();
requestAnimationFrame(animate);
};
requestAnimationFrame(animate);
}
};
});
System.register('./tests.spec.js', [], function (exports_1, context_1) {
'use strict';
var __moduleName = context_1 && context_1.id;
function spec() {
describe('example', function () {
it('should pass', function () {
expect(true).toBeTruthy();
});
});
}
exports_1('spec', spec);
return {
setters: [],
execute: function () {
}
};
});
System.register('./tests.js', ['./tests.spec.js'], function (exports_1, context_1) {
'use strict';
var tests_spec_1, HtmlReporter, config, specifications;
var __moduleName = context_1 && context_1.id;
function getContainer() {
var element = document.body;
return element;
}
function onChangeOption(key, value) {
switch (key) {
case 'failFast': {
config.failFast = !config.failFast;
break;
}
case 'throwFailures': {
config.oneFailurePerSpec = !config.oneFailurePerSpec;
break;
}
case 'random': {
config.random = !config.random;
break;
}
case 'hideDisabled': {
config.hideDisabled = !config.hideDisabled;
break;
}
default: {
console.warn('navigateWithNewParam(key=' + key + ', value=' + JSON.stringify(value));
}
}
runTests();
}
function addSpec(value) {
specifications.push(value);
return '';
}
function addSeed(_seed) {
return '';
}
function runTests() {
var jasmineCore = jasmineRequire.core(jasmineRequire);
jasmineRequire.html(jasmineCore);
var env = jasmineCore.getEnv();
var jasmineInterface = jasmineRequire.interface(jasmineCore, env);
extend(window, jasmineInterface);
var htmlReporter = new HtmlReporter({
env: env,
addToExistingQueryString: function (key, value) {
switch (key) {
case 'spec': {
return addSpec(value);
break;
}
case 'seed': {
return addSeed(parseInt(value, 10));
break;
}
default: {
throw new Error('Unknown key: ' + key);
}
}
},
navigateWithNewParam: onChangeOption,
getContainer: getContainer,
createElement: function () {
return document.createElement.apply(document, arguments);
},
createTextNode: function () {
return document.createTextNode.apply(document, arguments);
},
timer: new jasmine.Timer(),
filterSpecs: true
});
env.addReporter(jasmineInterface.jsApiReporter);
env.addReporter(htmlReporter);
env.configure(config);
htmlReporter.initialize();
describe('spec', tests_spec_1.spec);
env.execute();
}
function extend(destination, source) {
for (var property in source) {
if (source.hasOwnProperty(property)) {
destination[property] = source[property];
}
}
return destination;
}
return {
setters: [function (tests_spec_1_1) {
tests_spec_1 = tests_spec_1_1;
}],
execute: function () {
HtmlReporter = function () {
var ResultsNode = function () {
function ResultsNode(result, type, parent) {
this.result = result;
this.type = type;
this.parent = parent;
this.children = [];
}
ResultsNode.prototype.addChild = function (result, type) {
this.children.push(new ResultsNode(result, type, this));
};
ResultsNode.prototype.last = function () {
return this.children[this.children.length - 1];
};
ResultsNode.prototype.updateResult = function (result) {
this.result = result;
};
return ResultsNode;
}();
var ResultsStateBuilder = function () {
function ResultsStateBuilder() {
this.topResults = new ResultsNode({ description: '' }, 'suite', null);
this.currentParent = this.topResults;
this.specsExecuted = 0;
this.failureCount = 0;
this.pendingSpecCount = 0;
}
ResultsStateBuilder.prototype.suiteStarted = function (result) {
this.currentParent.addChild(result, 'suite');
this.currentParent = this.currentParent.last();
};
ResultsStateBuilder.prototype.suiteDone = function (result) {
this.currentParent.updateResult(result);
if (this.currentParent !== this.topResults) {
this.currentParent = this.currentParent.parent;
}
if (result.status === 'failed') {
this.failureCount++;
}
};
ResultsStateBuilder.prototype.specStarted = function (_report) {
};
ResultsStateBuilder.prototype.specDone = function (result) {
this.currentParent.addChild(result, 'spec');
if (result.status !== 'excluded') {
this.specsExecuted++;
}
if (result.status === 'failed') {
this.failureCount++;
}
if (result.status === 'pending') {
this.pendingSpecCount++;
}
};
return ResultsStateBuilder;
}();
var HtmlReporter = function () {
function HtmlReporter(options) {
this.failures = [];
this.deprecationWarnings = [];
this.stateBuilder = new ResultsStateBuilder();
this.config = function () {
return options.env && options.env.configuration() || {};
};
this.getContainer = options.getContainer;
this.createElement = options.createElement;
this.createTextNode = options.createTextNode;
this.navigateWithNewParam = options.navigateWithNewParam || function () {
};
this.addToExistingQueryString = options.addToExistingQueryString || defaultQueryString;
this.filterSpecs = options.filterSpecs;
this.summary = createDom(this, 'div', { className: 'jasmine-summary' });
}
HtmlReporter.prototype.initialize = function () {
clearPrior(this);
this.htmlReporterMain = createDom(this, 'div', { className: 'jasmine_html-reporter' }, createDom(this, 'div', { className: 'jasmine-banner' }, this.createAnchor({
className: 'jasmine-title',
href: 'http://jasmine.github.io/',
target: '_blank'
}), createDom(this, 'span', { className: 'jasmine-version' }, jasmine.version)), createDom(this, 'ul', { className: 'jasmine-symbol-summary' }), createDom(this, 'div', { className: 'jasmine-alert' }), createDom(this, 'div', { className: 'jasmine-results' }, createDom(this, 'div', { className: 'jasmine-failures' })));
this.getContainer().appendChild(this.htmlReporterMain);
};
HtmlReporter.prototype.jasmineStarted = function (options) {
this.totalSpecsDefined = options.totalSpecsDefined || 0;
};
HtmlReporter.prototype.suiteStarted = function (result) {
this.stateBuilder.suiteStarted(result);
};
HtmlReporter.prototype.suiteDone = function (result) {
this.stateBuilder.suiteDone(result);
if (result.status === 'failed') {
this.failures.push(failureDom(result, this));
}
addDeprecationWarnings(result, this);
};
HtmlReporter.prototype.specStarted = function (result) {
this.stateBuilder.specStarted(result);
};
HtmlReporter.prototype.specDone = function (result) {
this.stateBuilder.specDone(result);
if (noExpectations(result)) {
var noSpecMsg = 'Spec "' + result.fullName + '" has no expectations.';
if (result.status === 'failed') {
console.error(noSpecMsg);
} else {
console.warn(noSpecMsg);
}
}
if (!this.symbols) {
this.symbols = find('.jasmine-symbol-summary', this, 'specDone');
}
this.symbols.appendChild(createDom(this, 'li', {
className: this.classNameFromSpecReport(result),
id: 'spec_' + result.id,
title: result.fullName
}));
if (result.status === 'failed') {
this.failures.push(failureDom(result, this));
}
addDeprecationWarnings(result, this);
};
HtmlReporter.prototype.classNameFromSpecReport = function (report) {
return noExpectations(report) && report.status === 'passed' ? 'jasmine-empty' : this.classNameFromStatus(report.status);
};
HtmlReporter.prototype.classNameFromStatus = function (status) {
switch (status) {
case 'excluded':
case 'passed': {
return this.config().hideDisabled ? 'jasmine-excluded-no-display' : 'jasmine-excluded';
}
case 'pending':
return 'jasmine-pending';
case 'failed':
return 'jasmine-failed';
default: {
throw new Error('classNameFromStatus(\'' + status + '\')');
}
}
};
HtmlReporter.prototype.jasmineDone = function (doneResult) {
var _this = this;
var banner = find('.jasmine-banner', this, 'jasmineDone');
var alert = find('.jasmine-alert', this, 'jasmineDone');
var order = doneResult && doneResult.order;
alert.appendChild(createDom(this, 'span', { className: 'jasmine-duration' }, 'finished in ' + doneResult.totalTime / 1000 + 's'));
banner.appendChild(optionsMenu(this.config(), this));
if (this.stateBuilder.specsExecuted < this.totalSpecsDefined) {
var skippedMessage = 'Ran ' + this.stateBuilder.specsExecuted + ' of ' + this.totalSpecsDefined + ' specs - run all';
var skippedLink = this.addToExistingQueryString('spec', '');
alert.appendChild(createDom(this, 'span', { className: 'jasmine-bar jasmine-skipped' }, this.createAnchor({
href: skippedLink,
title: 'Run all specs'
}, skippedMessage)));
}
var statusBarMessage = '';
var statusBarClassName = 'jasmine-overall-result jasmine-bar ';
var globalFailures = doneResult && doneResult.failedExpectations || [];
var failed = this.stateBuilder.failureCount + globalFailures.length > 0;
if (this.totalSpecsDefined > 0 || failed) {
statusBarMessage += pluralize('spec', this.stateBuilder.specsExecuted) + ', ' + pluralize('failure', this.stateBuilder.failureCount);
if (this.stateBuilder.pendingSpecCount) {
statusBarMessage += ', ' + pluralize('pending spec', this.stateBuilder.pendingSpecCount);
}
}
if (doneResult.overallStatus === 'passed') {
statusBarClassName += ' jasmine-passed ';
} else if (doneResult.overallStatus === 'incomplete') {
statusBarClassName += ' jasmine-incomplete ';
statusBarMessage = 'Incomplete: ' + doneResult.incompleteReason + ', ' + statusBarMessage;
} else {
statusBarClassName += ' jasmine-failed ';
}
if (order && order.random) {
var seedBar = createDom(this, 'span', { className: 'jasmine-seed-bar' }, ', randomized with seed ', this.createAnchor({
title: 'randomized with seed ' + order.seed,
href: seedHref(order.seed, this)
}, order.seed));
alert.appendChild(createDom(this, 'span', { className: statusBarClassName }, statusBarMessage, seedBar));
} else {
alert.appendChild(createDom(this, 'span', { className: statusBarClassName }, statusBarMessage));
}
var errorBarClassName = 'jasmine-bar jasmine-errored';
var afterAllMessagePrefix = 'AfterAll ';
var _Tt0La = Date.now();
for (var _i = 0, globalFailures_1 = globalFailures; _i < globalFailures_1.length; _i++) {
if (Date.now() - _Tt0La > 1000) {
throw new Error('Infinite loop suspected after 1000 milliseconds.');
}
{
var globalFailure = globalFailures_1[_i];
alert.appendChild(createDom(this, 'span', { className: errorBarClassName }, globalFailureMessage(globalFailure)));
}
}
function globalFailureMessage(failure) {
if (failure.globalErrorType === 'load') {
var prefix = 'Error during loading: ' + failure.message;
if (failure.filename) {
return prefix + ' in ' + failure.filename + ' line ' + failure.lineno;
} else {
return prefix;
}
} else {
return afterAllMessagePrefix + failure.message;
}
}
addDeprecationWarnings(doneResult, this);
var warningBarClassName = 'jasmine-bar jasmine-warning';
var _hAF3g = Date.now();
for (var _a = 0, _b = this.deprecationWarnings; _a < _b.length; _a++) {
if (Date.now() - _hAF3g > 1000) {
throw new Error('Infinite loop suspected after 1000 milliseconds.');
}
{
var deprecationWarning = _b[_a];
alert.appendChild(createDom(this, 'span', { className: warningBarClassName }, 'DEPRECATION: ' + deprecationWarning));
}
}
var results = find('.jasmine-results', this, 'jasmineDone');
results.appendChild(this.summary);
summaryList(this.stateBuilder.topResults, this.summary, this);
if (this.failures.length) {
alert.appendChild(createDom(this, 'span', { className: 'jasmine-menu jasmine-bar jasmine-spec-list' }, createDom(this, 'span', {}, 'Spec List | '), this.createAnchor({
className: 'jasmine-failures-menu',
href: '#'
}, 'Failures')));
alert.appendChild(createDom(this, 'span', { className: 'jasmine-menu jasmine-bar jasmine-failure-list' }, this.createAnchor({
className: 'jasmine-spec-list-menu',
href: '#'
}, 'Spec List'), createDom(this, 'span', {}, ' | Failures ')));
findAnchor('.jasmine-failures-menu', this).onclick = function () {
setMenuModeTo('jasmine-failure-list', _this);
return false;
};
findAnchor('.jasmine-spec-list-menu', this).onclick = function () {
setMenuModeTo('jasmine-spec-list', _this);
return false;
};
setMenuModeTo('jasmine-failure-list', this);
var failureNode = find('.jasmine-failures', this, 'jasmineDone');
var _gc1Tt = Date.now();
for (var _c = 0, _d = this.failures; _c < _d.length; _c++) {
if (Date.now() - _gc1Tt > 1000) {
throw new Error('Infinite loop suspected after 1000 milliseconds.');
}
{
var failure = _d[_c];
failureNode.appendChild(failure);
}
}
}
};
HtmlReporter.prototype.createAnchor = function (attrs, text) {
var placeholder = {};
if (attrs.className) {
placeholder.className = attrs.className;
}
if (attrs.title) {
placeholder.title = attrs.title;
}
if (attrs.target) {
placeholder.target = attrs.target;
}
if (attrs.href) {
if (attrs.target === '_blank') {
placeholder.href = attrs.href;
}
}
if (typeof text === 'string') {
return createDom(this, 'a', placeholder, text);
} else {
return createDom(this, 'a', placeholder);
}
};
return HtmlReporter;
}();
function failureDom(result, reporter) {
var failure = createDom(reporter, 'div', { className: 'jasmine-spec-detail jasmine-failed' }, failureDescription(result, reporter.stateBuilder.currentParent, reporter), createDom(reporter, 'div', { className: 'jasmine-messages' }));
var messages = failure.childNodes[1];
var _x6RwI = Date.now();
for (var _i = 0, _a = result.failedExpectations; _i < _a.length; _i++) {
if (Date.now() - _x6RwI > 1000) {
throw new Error('Infinite loop suspected after 1000 milliseconds.');
}
{
var expectation = _a[_i];
messages.appendChild(createDom(reporter, 'div', { className: 'jasmine-result-message' }, expectation.message));
messages.appendChild(createDom(reporter, 'div', { className: 'jasmine-stack-trace' }, expectation.stack));
}
}
if (result.failedExpectations.length === 0) {
messages.appendChild(createDom(reporter, 'div', { className: 'jasmine-result-message' }, 'Spec has no expectations'));
}
return failure;
}
function summaryList(resultsTree, domParent, reporter) {
var specListNode;
var _9j242 = Date.now();
for (var _i = 0, _a = resultsTree.children; _i < _a.length; _i++) {
if (Date.now() - _9j242 > 1000) {
throw new Error('Infinite loop suspected after 1000 milliseconds.');
}
{
var resultNode = _a[_i];
if (reporter.filterSpecs && !hasActiveSpec(resultNode)) {
continue;
}
if (resultNode.type === 'suite') {
var result = resultNode.result;
var suiteListNode = createDom(reporter, 'ul', {
className: 'jasmine-suite',
id: 'suite-' + result.id
}, createDom(reporter, 'li', { className: 'jasmine-suite-detail jasmine-' + result.status }, reporter.createAnchor({ href: specHref(result, reporter) }, result.description)));
summaryList(resultNode, suiteListNode, reporter);
domParent.appendChild(suiteListNode);
}
if (resultNode.type === 'spec') {
var result = resultNode.result;
if (domParent.getAttribute('class') !== 'jasmine-specs') {
specListNode = createDom(reporter, 'ul', { className: 'jasmine-specs' });
domParent.appendChild(specListNode);
}
var specDescription = result.description;
if (noExpectations(result)) {
specDescription = 'SPEC HAS NO EXPECTATIONS ' + specDescription;
}
if (result.status === 'pending' && result.pendingReason !== '') {
specDescription = specDescription + ' PENDING WITH MESSAGE: ' + result.pendingReason;
}
specListNode.appendChild(createDom(reporter, 'li', {
className: 'jasmine-' + result.status,
id: 'spec-' + result.id
}, reporter.createAnchor({ href: specHref(result, reporter) }, specDescription)));
}
}
}
}
function optionsMenu(config, reporter) {
var optionsMenuDom = createDom(reporter, 'div', { className: 'jasmine-run-options' }, createDom(reporter, 'span', { className: 'jasmine-trigger' }, 'Options'), createDom(reporter, 'div', { className: 'jasmine-payload' }, createDom(reporter, 'div', { className: 'jasmine-stop-on-failure' }, createDom(reporter, 'input', {
className: 'jasmine-fail-fast',
id: 'jasmine-fail-fast',
type: 'checkbox'
}), createDom(reporter, 'label', {
className: 'jasmine-label',
for: 'jasmine-fail-fast'
}, 'stop execution on spec failure')), createDom(reporter, 'div', { className: 'jasmine-throw-failures' }, createDom(reporter, 'input', {
className: 'jasmine-throw',
id: 'jasmine-throw-failures',
type: 'checkbox'
}), createDom(reporter, 'label', {
className: 'jasmine-label',
for: 'jasmine-throw-failures'
}, 'stop spec on expectation failure')), createDom(reporter, 'div', { className: 'jasmine-random-order' }, createDom(reporter, 'input', {
className: 'jasmine-random',
id: 'jasmine-random-order',
type: 'checkbox'
}), createDom(reporter, 'label', {
className: 'jasmine-label',
for: 'jasmine-random-order'
}, 'run tests in random order')), createDom(reporter, 'div', { className: 'jasmine-hide-disabled' }, createDom(reporter, 'input', {
className: 'jasmine-disabled',
id: 'jasmine-hide-disabled',
type: 'checkbox'
}), createDom(reporter, 'label', {
className: 'jasmine-label',
for: 'jasmine-hide-disabled'
}, 'hide disabled tests'))));
var failFastCheckbox = optionsMenuDom.querySelector('#jasmine-fail-fast');
failFastCheckbox.checked = config.failFast ? true : false;
failFastCheckbox.onclick = function () {
reporter.navigateWithNewParam('failFast', !config.failFast);
};
var throwCheckbox = optionsMenuDom.querySelector('#jasmine-throw-failures');
throwCheckbox.checked = config.oneFailurePerSpec ? true : false;
throwCheckbox.onclick = function () {
reporter.navigateWithNewParam('throwFailures', !config.oneFailurePerSpec);
};
var randomCheckbox = optionsMenuDom.querySelector('#jasmine-random-order');
randomCheckbox.checked = config.random ? true : false;
randomCheckbox.onclick = function () {
reporter.navigateWithNewParam('random', !config.random);
};
var hideDisabled = optionsMenuDom.querySelector('#jasmine-hide-disabled');
hideDisabled.checked = config.hideDisabled ? true : false;
hideDisabled.onclick = function () {
reporter.navigateWithNewParam('hideDisabled', !config.hideDisabled);
};
var optionsTrigger = optionsMenuDom.querySelector('.jasmine-trigger');
var optionsPayload = optionsMenuDom.querySelector('.jasmine-payload');
var isOpen = /\bjasmine-open\b/;
optionsTrigger.onclick = function () {
if (isOpen.test(optionsPayload.className)) {
optionsPayload.className = optionsPayload.className.replace(isOpen, '');
} else {
optionsPayload.className += ' jasmine-open';
}
};
return optionsMenuDom;
}
function failureDescription(result, suite, reporter) {
var wrapper = createDom(reporter, 'div', { className: 'jasmine-description' }, reporter.createAnchor({
title: result.description,
href: specHref(result, reporter)
}, result.description));
var suiteLink;
var _MJ5UB = Date.now();
while (suite && suite.parent) {
if (Date.now() - _MJ5UB > 1000) {
throw new Error('Infinite loop suspected after 1000 milliseconds.');
}
{
wrapper.insertBefore(reporter.createTextNode(' > '), wrapper.firstChild);
suiteLink = reporter.createAnchor({ href: suiteHref(suite, reporter) }, suite.result.description);
wrapper.insertBefore(suiteLink, wrapper.firstChild);
suite = suite.parent;
}
}
return wrapper;
}
function suiteHref(suite, reporter) {
var els = [];
var _jXXue = Date.now();
while (suite && suite.parent) {
if (Date.now() - _jXXue > 1000) {
throw new Error('Infinite loop suspected after 1000 milliseconds.');
}
{
els.unshift(suite.result.description);
suite = suite.parent;
}
}
return reporter.addToExistingQueryString('spec', els.join(' '));
}
function addDeprecationWarnings(result, reporter) {
if (result && result.deprecationWarnings) {
var _3p0dJ = Date.now();
for (var _i = 0, _a = result.deprecationWarnings; _i < _a.length; _i++) {
if (Date.now() - _3p0dJ > 1000) {
throw new Error('Infinite loop suspected after 1000 milliseconds.');
}
{
var deprecationWarning = _a[_i];
var warning = deprecationWarning.message;
reporter.deprecationWarnings.push(warning);
}
}
}
}
function findAnchor(selector, reporter) {
var element = find(selector, reporter, 'findAnchor');
if (element instanceof HTMLAnchorElement) {
return element;
} else {
throw new Error(selector + ' is not an HTMLAnchorElement');
}
}
function find(selector, reporter, _origin) {
var selectors = '.jasmine_html-reporter ' + selector;
var element = reporter.getContainer().querySelector(selectors);
if (element) {
return element;
} else {
throw new Error('Unable to find selectors ' + JSON.stringify(selectors));
}
}
function clearPrior(reporter) {
try {
var oldReporter = find('', reporter, 'clearPrior');
reporter.getContainer().removeChild(oldReporter);
} catch (e) {
}
}
function createDom(factory, type, attrs) {
var _children = [];
var _b577C = Date.now();
for (var _i = 3; _i < arguments.length; _i++) {
if (Date.now() - _b577C > 1000) {
throw new Error('Infinite loop suspected after 1000 milliseconds.');
}
{
_children[_i - 3] = arguments[_i];
}
}
var el = factory.createElement(type);
var _VjCjL = Date.now();
for (var i = 3; i < arguments.length; i++) {
if (Date.now() - _VjCjL > 1000) {
throw new Error('Infinite loop suspected after 1000 milliseconds.');
}
{
var child = arguments[i];
if (typeof child === 'string') {
el.appendChild(factory.createTextNode(child));
} else {
if (child) {
el.appendChild(child);
}
}
}
}
for (var attr in attrs) {
if (attr === 'className') {
el[attr] = attrs[attr];
} else {
el.setAttribute(attr, attrs[attr]);
}
}
return el;
}
function pluralize(singular, count) {
var word = count === 1 ? singular : singular + 's';
return '' + count + ' ' + word;
}
function specHref(result, reporter) {
return reporter.addToExistingQueryString('spec', result.fullName);
}
function seedHref(seed, reporter) {
return reporter.addToExistingQueryString('seed', seed);
}
function defaultQueryString(key, value) {
return '?' + key + '=' + value;
}
function setMenuModeTo(mode, reporter) {
reporter.htmlReporterMain.setAttribute('class', 'jasmine_html-reporter ' + mode);
}
function noExpectations(result) {
var allExpectations = result.failedExpectations.length + result.passedExpectations.length;
return allExpectations === 0 && (result.status === 'passed' || result.status === 'failed');
}
function hasActiveSpec(resultNode) {
if (resultNode.type === 'spec') {
var result = resultNode.result;
if (result.status !== 'excluded') {
return true;
}
}
if (resultNode.type === 'suite') {
var j = resultNode.children.length;
var _8H7Mp = Date.now();
for (var i = 0; i < j; i++) {
if (Date.now() - _8H7Mp > 1000) {
throw new Error('Infinite loop suspected after 1000 milliseconds.');
}
{
if (hasActiveSpec(resultNode.children[i])) {
return true;
}
}
}
}
return false;
}
return HtmlReporter;
}();
config = {
random: false,
failFast: false,
failSpecWithNoExpectations: false,
oneFailurePerSpec: false,
hideDisabled: false,
specFilter: void 0,
promise: void 0
};
specifications = [];
DomReady.ready(runTests).catch(function (e) {
return console.error(e);
});
}
};
});
</script>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<script src='https://jspm.io/system.js'></script>
</head>
<body>
<canvas id='canvas'></canvas>
<script>
System.import('./index.js')
</script>
</body>
</html>
import * as EIGHT from 'davinci-eight'
/**
* Wrapper around the WebGLRenderingContext providing the ContextManager interface.
*/
const engine = new EIGHT.Engine('canvas')
.size(500, 500)
.clearColor(0.1, 0.1, 0.1, 1.0)
.enable(EIGHT.Capability.DEPTH_TEST)
/**
* A collection of objects that can be rendered with a single draw method call.
*/
const scene = new EIGHT.Scene(engine)
/**
* Rendering information that applies to all objects.
*/
const ambients: EIGHT.Facet[] = []
/**
* Provides the viewing point and perspective transformation.
*/
const camera = new EIGHT.PerspectiveCamera()
camera.eye.scale(5)
ambients.push(camera)
/**
* Provides a light color and direction for Lambert shading.
*/
const dirLight = new EIGHT.DirectionalLight()
ambients.push(dirLight)
/**
* Controls the camera by accumulating mouse movements then moving and rotating the camera.
*/
const trackball = new EIGHT.TrackballControls(camera, window)
trackball.subscribe(engine.canvas)
trackball.noPan = true;
// Create drawables such as Arrow, Box, Curve, Grid, Sphere, Cylinder.
// Add them to the scene here...
const body = new EIGHT.Box(engine, { color: EIGHT.Color.blueviolet })
scene.add(body)
const stats = new Stats()
document.body.appendChild(stats.domElement)
/**
* Animates the scene.
*/
const animate = function(_timestamp: number) {
stats.begin()
engine.clear()
trackball.update()
dirLight.direction.copy(camera.look).sub(camera.eye)
// Manupulate the X (Position) and R (Attitude)
// properties of your scene objects here...
scene.render(ambients)
stats.end()
requestAnimationFrame(animate)
}
requestAnimationFrame(animate)
{
"description": "Tutorial",
"dependencies": {
"DomReady": "1.0.0",
"stats.js": "0.16.0",
"jasmine": "3.4.0",
"davinci-eight": "7.4.4"
},
"author": "David Geo Holmes",
"name": "",
"version": ""
}
body {
background-color: white;
}
body { background-color: #eeeeee; }
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<base href='/'>
<link rel='stylesheet' href='tests.css'>
</head>
<body>
</body>
</html>

Jasmine Testing Framework

Overview

The Jasmine Testing Framework

export function spec() {
describe('example', function() {
it('should pass', function() {
expect(true).toBeTruthy()
})
})
}
import { spec } from './tests.spec'
const HtmlReporter = (function() {
type ResultsNodeResult = jasmine.SuiteStartedReport | jasmine.SuiteDoneReport | jasmine.SpecDoneReport | { description: string }
class ResultsNode {
type: 'spec' | 'suite'
result: ResultsNodeResult
children: ResultsNode[]
parent: ResultsNode | null
constructor(result: ResultsNodeResult, type: 'spec' | 'suite', parent: ResultsNode | null) {
this.result = result
this.type = type
this.parent = parent
this.children = []
}
addChild(result: ResultsNodeResult, type: 'spec' | 'suite'): void {
this.children.push(new ResultsNode(result, type, this))
}
last(): ResultsNode {
return this.children[this.children.length - 1]
}
updateResult(result: ResultsNodeResult): void {
this.result = result
}
}
class ResultsStateBuilder {
topResults: ResultsNode
currentParent: ResultsNode
specsExecuted: number
failureCount: number
pendingSpecCount: number
constructor() {
this.topResults = new ResultsNode({ description: "" }, 'suite', null)
this.currentParent = this.topResults
this.specsExecuted = 0
this.failureCount = 0
this.pendingSpecCount = 0
}
suiteStarted(result: jasmine.SuiteStartedReport): void {
this.currentParent.addChild(result, 'suite')
this.currentParent = this.currentParent.last()
}
suiteDone(result: jasmine.SuiteDoneReport): void {
this.currentParent.updateResult(result)
if (this.currentParent !== this.topResults) {
this.currentParent = this.currentParent.parent as ResultsNode
}
if (result.status === 'failed') {
this.failureCount++
}
}
specStarted(_report: jasmine.SpecStartedReport): void {
// Do nothing
}
specDone(result: jasmine.SpecDoneReport) {
this.currentParent.addChild(result, 'spec')
if (result.status !== 'excluded') {
this.specsExecuted++
}
if (result.status === 'failed') {
this.failureCount++
}
if (result.status === 'pending') {
this.pendingSpecCount++
}
}
}
/**
* Customized HtmlReporter so that we can create placeholder hyperlinks.
*/
class HtmlReporter implements jasmine.Reporter {
config: () => jasmine.EnvConfiguration
failures: HTMLElement[] = []
getContainer: () => HTMLElement
createElement: (type: 'div' | 'a' | 'ul' | 'span') => HTMLElement
createTextNode: (text: string) => Text
navigateWithNewParam: any
/**
* Use to generate href attributes for HTMLAnchorElements.
*/
addToExistingQueryString: (key: 'seed' | 'spec', value: string) => string
filterSpecs: any
symbols: Element
deprecationWarnings: string[] = []
summary: HTMLElement
htmlReporterMain: HTMLElement
totalSpecsDefined: number
stateBuilder = new ResultsStateBuilder()
constructor(options: jasmine.HtmlReporterOptions) {
this.config = function() {
return (options.env && options.env.configuration()) || {}
}
this.getContainer = options.getContainer
this.createElement = options.createElement
this.createTextNode = options.createTextNode
this.navigateWithNewParam = options.navigateWithNewParam || function() { }
this.addToExistingQueryString = options.addToExistingQueryString || defaultQueryString
this.filterSpecs = options.filterSpecs
this.summary = createDom(this, 'div', { className: 'jasmine-summary' })
}
initialize() {
clearPrior(this)
this.htmlReporterMain = createDom(this,
'div',
{ className: 'jasmine_html-reporter' },
createDom(this,
'div',
{ className: 'jasmine-banner' },
this.createAnchor({ className: 'jasmine-title', href: 'http://jasmine.github.io/', target: '_blank' }),
createDom(this, 'span', { className: 'jasmine-version' }, jasmine.version)
),
createDom(this, 'ul', { className: 'jasmine-symbol-summary' }),
createDom(this, 'div', { className: 'jasmine-alert' }),
createDom(this, 'div', { className: 'jasmine-results' }, createDom(this, 'div', { className: 'jasmine-failures' }))
)
this.getContainer().appendChild(this.htmlReporterMain)
}
jasmineStarted(options: jasmine.JasmineStartedReport) {
this.totalSpecsDefined = options.totalSpecsDefined || 0
}
suiteStarted(result: jasmine.SuiteStartedReport) {
this.stateBuilder.suiteStarted(result)
}
suiteDone(result: jasmine.SuiteDoneReport) {
this.stateBuilder.suiteDone(result)
if (result.status === 'failed') {
this.failures.push(failureDom(result, this))
}
addDeprecationWarnings(result, this)
}
specStarted(result: jasmine.SpecStartedReport) {
this.stateBuilder.specStarted(result)
}
specDone(result: jasmine.SpecDoneReport) {
this.stateBuilder.specDone(result)
if (noExpectations(result)) {
const noSpecMsg = `Spec "${result.fullName}" has no expectations.`
if (result.status === 'failed') {
console.error(noSpecMsg)
} else {
console.warn(noSpecMsg)
}
}
if (!this.symbols) {
this.symbols = find('.jasmine-symbol-summary', this, 'specDone')
}
this.symbols.appendChild(
createDom(this, 'li', {
className: this.classNameFromSpecReport(result),
id: `spec_${result.id}`,
title: result.fullName
})
)
if (result.status === 'failed') {
this.failures.push(failureDom(result, this))
}
addDeprecationWarnings(result, this)
}
classNameFromSpecReport(report: jasmine.SpecDoneReport) {
return noExpectations(report) && (report.status === 'passed') ? 'jasmine-empty' : this.classNameFromStatus(report.status)
}
classNameFromStatus(status: 'excluded' | 'passed' | 'failed' | 'disabled' | 'pending'): 'jasmine-excluded-no-display' | 'jasmine-excluded' | 'jasmine-pending' | 'jasmine-failed' | 'jasmine-' {
switch (status) {
case 'excluded':
case 'passed': {
return this.config().hideDisabled ? 'jasmine-excluded-no-display' : 'jasmine-excluded'
}
case 'pending': return 'jasmine-pending'
case 'failed': return 'jasmine-failed'
default: {
throw new Error(`classNameFromStatus('${status}')`)
}
}
}
jasmineDone(doneResult: jasmine.JasmineDoneReport) {
const banner = find('.jasmine-banner', this, 'jasmineDone')
const alert = find('.jasmine-alert', this, 'jasmineDone')
const order = doneResult && doneResult.order
alert.appendChild(
createDom(this, 'span', { className: 'jasmine-duration' }, 'finished in ' + doneResult.totalTime / 1000 + 's')
)
banner.appendChild(optionsMenu(this.config(), this))
if (this.stateBuilder.specsExecuted < this.totalSpecsDefined) {
const skippedMessage =
'Ran ' +
this.stateBuilder.specsExecuted +
' of ' +
this.totalSpecsDefined +
' specs - run all'
const skippedLink = this.addToExistingQueryString('spec', '')
alert.appendChild(
createDom(this,
'span',
{ className: 'jasmine-bar jasmine-skipped' },
this.createAnchor({ href: skippedLink, title: 'Run all specs' }, skippedMessage)
)
)
}
let statusBarMessage = ''
let statusBarClassName = 'jasmine-overall-result jasmine-bar '
const globalFailures = (doneResult && doneResult.failedExpectations) || []
const failed = this.stateBuilder.failureCount + globalFailures.length > 0
if (this.totalSpecsDefined > 0 || failed) {
statusBarMessage += pluralize('spec', this.stateBuilder.specsExecuted) + ', ' + pluralize('failure', this.stateBuilder.failureCount)
if (this.stateBuilder.pendingSpecCount) {
statusBarMessage += ', ' + pluralize('pending spec', this.stateBuilder.pendingSpecCount)
}
}
if (doneResult.overallStatus === 'passed') {
statusBarClassName += ' jasmine-passed '
} else if (doneResult.overallStatus === 'incomplete') {
statusBarClassName += ' jasmine-incomplete '
statusBarMessage =
'Incomplete: ' +
doneResult.incompleteReason +
', ' +
statusBarMessage
} else {
statusBarClassName += ' jasmine-failed '
}
if (order && order.random) {
const seedBar = createDom(this,
'span',
{ className: 'jasmine-seed-bar' },
', randomized with seed ',
this.createAnchor({ title: 'randomized with seed ' + order.seed, href: seedHref(order.seed, this) }, order.seed)
)
alert.appendChild(createDom(this, 'span', { className: statusBarClassName }, statusBarMessage, seedBar))
}
else {
alert.appendChild(createDom(this, 'span', { className: statusBarClassName }, statusBarMessage))
}
const errorBarClassName = 'jasmine-bar jasmine-errored'
const afterAllMessagePrefix = 'AfterAll '
for (const globalFailure of globalFailures) {
alert.appendChild(
createDom(this,
'span',
{ className: errorBarClassName },
globalFailureMessage(globalFailure)
)
)
}
function globalFailureMessage(failure: { globalErrorType: 'load'; message: string; filename: string; lineno: number }) {
if (failure.globalErrorType === 'load') {
const prefix = 'Error during loading: ' + failure.message
if (failure.filename) {
return (
prefix + ' in ' + failure.filename + ' line ' + failure.lineno
)
} else {
return prefix
}
} else {
return afterAllMessagePrefix + failure.message
}
}
addDeprecationWarnings(doneResult, this)
const warningBarClassName = 'jasmine-bar jasmine-warning'
for (const deprecationWarning of this.deprecationWarnings) {
alert.appendChild(
createDom(this,
'span',
{ className: warningBarClassName },
'DEPRECATION: ' + deprecationWarning
)
)
}
const results = find('.jasmine-results', this, 'jasmineDone')
results.appendChild(this.summary)
summaryList(this.stateBuilder.topResults, this.summary, this)
if (this.failures.length) {
alert.appendChild(
createDom(this,
'span',
{ className: 'jasmine-menu jasmine-bar jasmine-spec-list' },
createDom(this, 'span', {}, 'Spec List | '),
this.createAnchor({ className: 'jasmine-failures-menu', href: '#' }, 'Failures')
)
)
alert.appendChild(
createDom(this,
'span',
{ className: 'jasmine-menu jasmine-bar jasmine-failure-list' },
this.createAnchor({ className: 'jasmine-spec-list-menu', href: '#' }, 'Spec List'),
createDom(this, 'span', {}, ' | Failures ')
)
)
findAnchor('.jasmine-failures-menu', this).onclick = () => {
setMenuModeTo('jasmine-failure-list', this)
return false
}
findAnchor('.jasmine-spec-list-menu', this).onclick = () => {
setMenuModeTo('jasmine-spec-list', this)
return false
}
setMenuModeTo('jasmine-failure-list', this)
const failureNode = find('.jasmine-failures', this, 'jasmineDone')
for (const failure of this.failures) {
failureNode.appendChild(failure)
}
}
}
/**
* Intercept all calls to create HTMLAnchorElement(s) so that we can create
* placeholder hyperlinks that don't navigate anywhere.
*/
public createAnchor(attrs: { className?: string; href?: string; title?: string; target?: '_blank' }, text?: string): HTMLAnchorElement {
const placeholder: { className?: string; href?: string; title?: string; target?: string } = {}
if (attrs.className) {
placeholder.className = attrs.className
}
if (attrs.title) {
placeholder.title = attrs.title
}
if (attrs.target) {
placeholder.target = attrs.target
}
if (attrs.href) {
if (attrs.target === '_blank') {
placeholder.href = attrs.href
}
}
if (typeof text === 'string') {
return createDom(this, 'a', placeholder, text) as HTMLAnchorElement
}
else {
return createDom(this, 'a', placeholder) as HTMLAnchorElement
}
}
}
function failureDom(result: jasmine.SuiteDoneReport | jasmine.SpecDoneReport, reporter: HtmlReporter) {
const failure = createDom(reporter,
'div',
{ className: 'jasmine-spec-detail jasmine-failed' },
failureDescription(result, reporter.stateBuilder.currentParent, reporter),
createDom(reporter, 'div', { className: 'jasmine-messages' })
)
const messages = failure.childNodes[1]
for (const expectation of result.failedExpectations) {
messages.appendChild(createDom(reporter, 'div', { className: 'jasmine-result-message' }, expectation.message))
messages.appendChild(createDom(reporter, 'div', { className: 'jasmine-stack-trace' }, expectation.stack)
)
}
if (result.failedExpectations.length === 0) {
messages.appendChild(createDom(reporter, 'div', { className: 'jasmine-result-message' }, 'Spec has no expectations'))
}
return failure
}
function summaryList(resultsTree: ResultsNode, domParent: HTMLElement, reporter: HtmlReporter) {
let specListNode: any
for (const resultNode of resultsTree.children) {
if (reporter.filterSpecs && !hasActiveSpec(resultNode)) {
continue
}
if (resultNode.type === 'suite') {
const result = resultNode.result as jasmine.SuiteDoneReport
const suiteListNode = createDom(reporter,
'ul',
{ className: 'jasmine-suite', id: 'suite-' + result.id },
createDom(reporter, 'li', { className: 'jasmine-suite-detail jasmine-' + result.status },
reporter.createAnchor({ href: specHref(result, reporter) }, result.description)
)
)
summaryList(resultNode, suiteListNode, reporter)
domParent.appendChild(suiteListNode)
}
if (resultNode.type === 'spec') {
const result = resultNode.result as jasmine.SpecDoneReport
if (domParent.getAttribute('class') !== 'jasmine-specs') {
specListNode = createDom(reporter, 'ul', { className: 'jasmine-specs' })
domParent.appendChild(specListNode)
}
let specDescription = result.description
if (noExpectations(result)) {
specDescription = 'SPEC HAS NO EXPECTATIONS ' + specDescription
}
if (result.status === 'pending' && result.pendingReason !== '') {
specDescription =
specDescription +
' PENDING WITH MESSAGE: ' +
result.pendingReason
}
specListNode.appendChild(
createDom(reporter,
'li',
{
className: 'jasmine-' + result.status,
id: 'spec-' + result.id
},
reporter.createAnchor({ href: specHref(result, reporter) }, specDescription)
)
)
}
}
}
function optionsMenu(config: jasmine.EnvConfiguration, reporter: HtmlReporter) {
const optionsMenuDom = createDom(reporter,
'div',
{ className: 'jasmine-run-options' },
createDom(reporter, 'span', { className: 'jasmine-trigger' }, 'Options'),
createDom(reporter,
'div',
{ className: 'jasmine-payload' },
createDom(reporter,
'div',
{ className: 'jasmine-stop-on-failure' },
createDom(reporter, 'input', {
className: 'jasmine-fail-fast',
id: 'jasmine-fail-fast',
type: 'checkbox'
}),
createDom(reporter,
'label',
{ className: 'jasmine-label', for: 'jasmine-fail-fast' },
'stop execution on spec failure'
)
),
createDom(reporter,
'div',
{ className: 'jasmine-throw-failures' },
createDom(reporter, 'input', {
className: 'jasmine-throw',
id: 'jasmine-throw-failures',
type: 'checkbox'
}),
createDom(reporter,
'label',
{ className: 'jasmine-label', for: 'jasmine-throw-failures' },
'stop spec on expectation failure'
)
),
createDom(reporter,
'div',
{ className: 'jasmine-random-order' },
createDom(reporter, 'input', {
className: 'jasmine-random',
id: 'jasmine-random-order',
type: 'checkbox'
}),
createDom(reporter,
'label',
{ className: 'jasmine-label', for: 'jasmine-random-order' },
'run tests in random order'
)
),
createDom(reporter,
'div',
{ className: 'jasmine-hide-disabled' },
createDom(reporter, 'input', {
className: 'jasmine-disabled',
id: 'jasmine-hide-disabled',
type: 'checkbox'
}),
createDom(reporter,
'label',
{ className: 'jasmine-label', for: 'jasmine-hide-disabled' },
'hide disabled tests'
)
)
)
)
const failFastCheckbox: HTMLInputElement = optionsMenuDom.querySelector('#jasmine-fail-fast') as HTMLInputElement
failFastCheckbox.checked = config.failFast ? true : false
failFastCheckbox.onclick = function() {
reporter.navigateWithNewParam('failFast', !config.failFast)
}
const throwCheckbox: HTMLInputElement = optionsMenuDom.querySelector('#jasmine-throw-failures') as HTMLInputElement
throwCheckbox.checked = config.oneFailurePerSpec ? true : false
throwCheckbox.onclick = function() {
reporter.navigateWithNewParam('throwFailures', !config.oneFailurePerSpec)
}
const randomCheckbox = optionsMenuDom.querySelector('#jasmine-random-order') as HTMLInputElement
randomCheckbox.checked = config.random ? true : false
randomCheckbox.onclick = function() {
reporter.navigateWithNewParam('random', !config.random)
}
const hideDisabled = optionsMenuDom.querySelector('#jasmine-hide-disabled') as HTMLInputElement
hideDisabled.checked = config.hideDisabled ? true : false
hideDisabled.onclick = function() {
reporter.navigateWithNewParam('hideDisabled', !config.hideDisabled)
}
const optionsTrigger = optionsMenuDom.querySelector('.jasmine-trigger') as HTMLButtonElement
const optionsPayload = optionsMenuDom.querySelector('.jasmine-payload') as HTMLElement
const isOpen = /\bjasmine-open\b/
optionsTrigger.onclick = function() {
if (isOpen.test(optionsPayload.className)) {
optionsPayload.className = optionsPayload.className.replace(
isOpen,
''
)
} else {
optionsPayload.className += ' jasmine-open'
}
}
return optionsMenuDom
}
function failureDescription(result: jasmine.SuiteDoneReport | jasmine.SpecDoneReport, suite: ResultsNode, reporter: HtmlReporter) {
const wrapper = createDom(reporter,
'div',
{ className: 'jasmine-description' },
reporter.createAnchor({ title: result.description, href: specHref(result, reporter) }, result.description)
)
let suiteLink
while (suite && suite.parent) {
wrapper.insertBefore(reporter.createTextNode(' > '), wrapper.firstChild)
suiteLink = reporter.createAnchor({ href: suiteHref(suite, reporter) }, suite.result.description)
wrapper.insertBefore(suiteLink, wrapper.firstChild)
suite = suite.parent
}
return wrapper
}
function suiteHref(suite: { parent: any; result: any }, reporter: HtmlReporter) {
// console.lg(`suiteHref()`)
const els = []
while (suite && suite.parent) {
els.unshift(suite.result.description)
suite = suite.parent
}
return reporter.addToExistingQueryString('spec', els.join(' '))
}
function addDeprecationWarnings(result: jasmine.SpecDoneReport | jasmine.SuiteDoneReport | jasmine.JasmineDoneReport, reporter: HtmlReporter) {
if (result && result.deprecationWarnings) {
for (const deprecationWarning of result.deprecationWarnings) {
const warning = deprecationWarning.message
// if (!j$.util.arrayContains(warning)) {
reporter.deprecationWarnings.push(warning)
// }
}
}
}
function findAnchor(selector: string, reporter: HtmlReporter): HTMLAnchorElement {
const element = find(selector, reporter, 'findAnchor')
if (element instanceof HTMLAnchorElement) {
return element
}
else {
throw new Error(`${selector} is not an HTMLAnchorElement`)
}
}
function find(selector: string, reporter: HtmlReporter, _origin: 'findAnchor' | 'clearPrior' | 'specDone' | 'jasmineDone'): Element {
// console.lg(`find(selector=${JSON.stringify(selector)}, origin=${origin})`)
const selectors = '.jasmine_html-reporter ' + selector
const element = reporter.getContainer().querySelector(selectors)
if (element) {
return element
}
else {
throw new Error(`Unable to find selectors ${JSON.stringify(selectors)}`)
}
}
function clearPrior(reporter: HtmlReporter) {
try {
const oldReporter = find('', reporter, 'clearPrior')
reporter.getContainer().removeChild(oldReporter)
}
catch (e) {
// We end up here if the oldReporter does not exist.
// TODO: Perhaps we also need a find that does not throw?
}
}
function createDom(factory: jasmine.HtmlReporterFactory, type: 'div' | 'a' | 'ul' | 'li' | 'span' | 'label' | 'input', attrs: {}, ..._children: (string | HTMLElement)[]) {
const el = factory.createElement(type)
for (let i = 3; i < arguments.length; i++) {
const child = arguments[i]
if (typeof child === 'string') {
el.appendChild(factory.createTextNode(child))
} else {
if (child) {
el.appendChild(child)
}
}
}
for (const attr in attrs) {
if (attr === 'className') {
el[attr] = attrs[attr]
} else {
el.setAttribute(attr, attrs[attr])
}
}
return el
}
function pluralize(singular: string, count: number): string {
const word = count === 1 ? singular : singular + 's'
return '' + count + ' ' + word
}
function specHref(result: { fullName: string }, reporter: HtmlReporter) {
return reporter.addToExistingQueryString('spec', result.fullName)
}
function seedHref(seed: string, reporter: HtmlReporter) {
return reporter.addToExistingQueryString('seed', seed)
}
function defaultQueryString(key: 'spec' | 'seed', value: string): string {
return '?' + key + '=' + value
}
function setMenuModeTo(mode: string, reporter: HtmlReporter) {
reporter.htmlReporterMain.setAttribute('class', 'jasmine_html-reporter ' + mode)
}
function noExpectations(result: jasmine.SpecDoneReport) {
const allExpectations =
result.failedExpectations.length + result.passedExpectations.length
return (allExpectations === 0 && (result.status === 'passed' || result.status === 'failed'))
}
function hasActiveSpec(resultNode: ResultsNode): boolean {
if (resultNode.type === 'spec') {
const result = resultNode.result as (jasmine.SpecDoneReport)
if (result.status !== 'excluded') {
return true
}
}
if (resultNode.type === 'suite') {
const j = resultNode.children.length
for (let i = 0; i < j; i++) {
if (hasActiveSpec(resultNode.children[i])) {
return true
}
}
}
return false
}
return HtmlReporter
})()
/**
* These configuration parameters determine how the tests are executed.
*/
const config: jasmine.EnvConfiguration = {
random: false,
failFast: false,
failSpecWithNoExpectations: false,
oneFailurePerSpec: false,
hideDisabled: false,
specFilter: void 0,
promise: void 0
}
const specifications: string[] = []
function getContainer(): HTMLElement {
const element = document.body
return element
}
function onChangeOption(key: 'failFast' | 'throwFailures' | 'random' | 'hideDisabled', value: string): void {
switch (key) {
case 'failFast': {
config.failFast = !config.failFast
break
}
case 'throwFailures': {
config.oneFailurePerSpec = !config.oneFailurePerSpec
break
}
case 'random': {
config.random = !config.random
break
}
case 'hideDisabled': {
config.hideDisabled = !config.hideDisabled
break
}
default: {
console.warn(`navigateWithNewParam(key=${key}, value=${JSON.stringify(value)}`)
}
}
runTests()
}
/**
* Generate an href for an HTMLAnchorElement.
*/
function addSpec(value: string): string {
specifications.push(value)
return ''
}
/**
* Generate an href for an HTMLAnchorElement.
*/
function addSeed(_seed: number): string {
// console.info(`onSeed(seed=${seed})`)
// config.seed = value
return ''
}
function runTests() {
const jasmineCore: jasmine.Jasmine = jasmineRequire.core(jasmineRequire)
// We shouldn't need to do this...
jasmineRequire.html(jasmineCore)
const env = jasmineCore.getEnv()
// Build the collection of functions that we use in our specs and put them in the global namespace.
const jasmineInterface = jasmineRequire.interface(jasmineCore, env)
/**
* Add all of the Jasmine global/public interface to the global scope, so a project can use the public interface directly.
* For example, calling `describe` in specs instead of `jasmine.getEnv().describe`.
*/
extend(window, jasmineInterface)
// const catchingExceptions = queryString.getParam("catch")
// env.catchExceptions(typeof catchingExceptions === "undefined" ? true : catchingExceptions)
const htmlReporter = new HtmlReporter({
env: env,
addToExistingQueryString: function(key: 'seed' | 'spec', value: string): string {
switch (key) {
case 'spec': {
return addSpec(value)
break
}
case 'seed': {
return addSeed(parseInt(value, 10))
break
}
default: {
throw new Error(`Unknown key: ${key}`)
}
}
},
navigateWithNewParam: onChangeOption,
getContainer,
createElement: function(): HTMLElement {
return document.createElement.apply(document, arguments)
},
createTextNode: function(): Text {
return document.createTextNode.apply(document, arguments)
},
timer: new jasmine.Timer(),
filterSpecs: true // Will only be true if query string contains 'spec'.
})
env.addReporter(jasmineInterface.jsApiReporter)
env.addReporter(htmlReporter)
env.configure(config)
htmlReporter.initialize()
// Declare your specification definitions here.
describe("spec", spec)
env.execute()
}
DomReady.ready(runTests).catch(e => console.error(e))
/*
* Helper function for extending the properties on objects.
*/
function extend<T>(destination: T, source: any): T {
for (const property in source) {
if (source.hasOwnProperty(property)) {
(<any> destination)[property] = source[property]
}
}
return destination
}
{
"allowJs": true,
"checkJs": true,
"declaration": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"jsx": "react",
"module": "system",
"noImplicitAny": true,
"noImplicitReturns": true,
"noImplicitThis": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"preserveConstEnums": true,
"removeComments": false,
"skipLibCheck": true,
"sourceMap": true,
"strictNullChecks": true,
"suppressImplicitAnyIndexErrors": true,
"target": "es5",
"traceResolution": true
}
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" type="text/css" href="https://thimble.mozilla.org/tutorial/tutorial.css">
</head>
<body>
<div class="tutorial">
<h1>STEMCstudio Tutorial</h1>
<p>
Edit this tutorial to provide step-by-step instructions to people remixing your project, including those who might be doing it on their own (without a mentor/facilitator/teacher). They will be able to toggle between the Preview pane and this Tutorial. Replace this section with an overview or some background about your project.
</p>
<p>
Check out the <a href="https://thimble.mozilla.org/tutorial/tutorial-style-guide.html" target="_blank">style guide</a> for HTML elements you can include.
</p>
<h3>Step-by-Step Instructions</h3>
<ol class="steps">
<li>
Add your first step here.
</li>
<li>
Add your second step here.
</li>
<li>
Add your third step here, and add more steps if needed.
</li>
<li>
Add a note of congratulations for completing the project and remixing the Web! Note any specific instructions for where to share the completed project if appropriate (e.g. Twitter hashtag, email to teacher, etc.)
</li>
</ol>
<pre class='code'>
const x = 27;
export default function(x: number, y: number) {
const that = {
};
return that;
}
</pre>
</div>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment