-
Notifications
You must be signed in to change notification settings - Fork 7
Add \ion, \positiveion, \negativeion commands for chemistry notation #45
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
e3e9346
50cca83
687c2ef
a4bd5dd
14575de
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -29,166 +29,170 @@ <h1>Unit Tests</h1> | |
| while (mock.firstChild) mock.firstChild.remove(); | ||
| }); | ||
|
|
||
| if (post_xunit_to) { | ||
| let xunit = ''; | ||
| Mocha.process.stdout.write = (line) => (xunit += line); | ||
| const runner = mocha.run(); | ||
|
|
||
| // the following is based on | ||
| // https://github.com/saucelabs-sample-scripts/JavaScript/blob/ | ||
| // 4946c5cf0ab7325dce5562881dba7c28e30989e5/reporting_mocha.js | ||
| const failedTests = []; | ||
| runner.on('fail', (test, err) => { | ||
| const flattenTitles = (test) => { | ||
| const titles = []; | ||
| while (test.parent.title) { | ||
| titles.push(test.parent.title); | ||
| test = test.parent; | ||
| } | ||
| return titles.reverse(); | ||
| }; | ||
| // Run after window load so the test bundle (mathquill.test.js, included at | ||
| // the end of the body) has registered its suites before mocha.run(). | ||
| window.addEventListener('load', () => { | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This seems to be an issue that is specific to Google Chrome (and maybe some others), but it does not occur in Firefox, and only happens when the dev server hot reloads. On initial page load the unit tests work as they should, but when the dev server hot reloads they don't. You need to refresh the page to get the unit tests to run again. I have noticed this before, but didn't care enough to look into it and fix it. Don't use a after that. Then start a new |
||
| if (post_xunit_to) { | ||
| let xunit = ''; | ||
| Mocha.process.stdout.write = (line) => (xunit += line); | ||
| const runner = mocha.run(); | ||
|
|
||
| // the following is based on | ||
| // https://github.com/saucelabs-sample-scripts/JavaScript/blob/ | ||
| // 4946c5cf0ab7325dce5562881dba7c28e30989e5/reporting_mocha.js | ||
| const failedTests = []; | ||
| runner.on('fail', (test, err) => { | ||
| const flattenTitles = (test) => { | ||
| const titles = []; | ||
| while (test.parent.title) { | ||
| titles.push(test.parent.title); | ||
| test = test.parent; | ||
| } | ||
| return titles.reverse(); | ||
| }; | ||
|
|
||
| failedTests.push({ | ||
| name: test.title, | ||
| result: false, | ||
| message: err.message, | ||
| stack: err.stack, | ||
| titles: flattenTitles(test) | ||
| failedTests.push({ | ||
| name: test.title, | ||
| result: false, | ||
| message: err.message, | ||
| stack: err.stack, | ||
| titles: flattenTitles(test) | ||
| }); | ||
| }); | ||
| }); | ||
|
|
||
| runner.on('end', () => { | ||
| fetch(post_xunit_to, { method: 'post', body: xunit }).then(() => { | ||
| window.mochaResults = runner.stats; | ||
| window.mochaResults.reports = failedTests; | ||
| }); | ||
| }); | ||
| } else { | ||
| const json = location.search.indexOf('json') >= 0; | ||
| const listTests = location.search.indexOf('listTests') >= 0; | ||
| const suiteMap = {}; | ||
| const runner = mocha.run(); | ||
|
|
||
| runner.on('suite', (suite) => { | ||
| const title = xmlEscape(suite.fullTitle()); | ||
| suiteMap[title] = { | ||
| assertions: [] | ||
| }; | ||
| if (listTests) { | ||
| suiteMap[title].assertions.push({ | ||
| elapsedTime: 0, | ||
| timestamp: 0, | ||
| result: true, | ||
| message: 'okay' | ||
| }); | ||
| } | ||
| }); | ||
|
|
||
| runner.on('pass', (test) => { | ||
| if (!listTests) { | ||
| const title = getTestSuiteTitle(test); | ||
| const elapsedTime = test.duration / 1000; | ||
| const timestamp = Date.now(); | ||
| suiteMap[title].assertions.push({ | ||
| elapsedTime: elapsedTime, | ||
| timestamp: timestamp, | ||
| result: true, | ||
| message: xmlEscape(test.title) | ||
| runner.on('end', () => { | ||
| fetch(post_xunit_to, { method: 'post', body: xunit }).then(() => { | ||
| window.mochaResults = runner.stats; | ||
| window.mochaResults.reports = failedTests; | ||
| }); | ||
| } | ||
| }); | ||
|
|
||
| runner.on('fail', (test, err) => { | ||
| if (!listTests) { | ||
| const title = getTestSuiteTitle(test); | ||
| const elapsedTime = test.duration / 1000; | ||
| const timestamp = Date.now(); | ||
| suiteMap[title].assertions.push({ | ||
| elapsedTime: elapsedTime, | ||
| timestamp: timestamp, | ||
| result: false, | ||
| message: xmlEscape(err.message), | ||
| stacktrace: xmlEscape(err.stack), | ||
| expected: true, | ||
| actual: false | ||
| }); | ||
| } | ||
| }); | ||
|
|
||
| runner.on('end', () => { | ||
| const moduleResults = []; | ||
| for (const suiteTitle in suiteMap) { | ||
| if (suiteMap.hasOwnProperty(suiteTitle)) { | ||
| const suiteResults = suiteMap[suiteTitle]; | ||
| let duration = 0; | ||
| for (const assertion of suiteResults.assertions) duration += assertion.elapsedTime; | ||
| moduleResults.push({ | ||
| name: suiteTitle, | ||
| assertions: suiteResults.assertions, | ||
| time: duration | ||
| }); | ||
| } else { | ||
| const json = location.search.indexOf('json') >= 0; | ||
| const listTests = location.search.indexOf('listTests') >= 0; | ||
| const suiteMap = {}; | ||
| const runner = mocha.run(); | ||
|
|
||
| runner.on('suite', (suite) => { | ||
| const title = xmlEscape(suite.fullTitle()); | ||
| suiteMap[title] = { | ||
| assertions: [] | ||
| }; | ||
| if (listTests) { | ||
| suiteMap[title].assertions.push({ | ||
| elapsedTime: 0, | ||
| timestamp: 0, | ||
| result: true, | ||
| message: 'okay' | ||
| }); | ||
| } | ||
| }); | ||
|
|
||
| runner.on('pass', (test) => { | ||
| if (!listTests) { | ||
| const title = getTestSuiteTitle(test); | ||
| const elapsedTime = test.duration / 1000; | ||
| const timestamp = Date.now(); | ||
| suiteMap[title].assertions.push({ | ||
| elapsedTime: elapsedTime, | ||
| timestamp: timestamp, | ||
| result: true, | ||
| message: xmlEscape(test.title) | ||
| }); | ||
| } | ||
| } | ||
| const testResults = { | ||
| modules: { mathquill: moduleResults }, | ||
| passes: runner.stats.passes, | ||
| failures: runner.stats.failures, | ||
| skips: 0 | ||
| }); | ||
|
|
||
| runner.on('fail', (test, err) => { | ||
| if (!listTests) { | ||
| const title = getTestSuiteTitle(test); | ||
| const elapsedTime = test.duration / 1000; | ||
| const timestamp = Date.now(); | ||
| suiteMap[title].assertions.push({ | ||
| elapsedTime: elapsedTime, | ||
| timestamp: timestamp, | ||
| result: false, | ||
| message: xmlEscape(err.message), | ||
| stacktrace: xmlEscape(err.stack), | ||
| expected: true, | ||
| actual: false | ||
| }); | ||
| } | ||
| }); | ||
|
|
||
| runner.on('end', () => { | ||
| const moduleResults = []; | ||
| for (const suiteTitle in suiteMap) { | ||
| if (suiteMap.hasOwnProperty(suiteTitle)) { | ||
| const suiteResults = suiteMap[suiteTitle]; | ||
| let duration = 0; | ||
| for (const assertion of suiteResults.assertions) duration += assertion.elapsedTime; | ||
| moduleResults.push({ | ||
| name: suiteTitle, | ||
| assertions: suiteResults.assertions, | ||
| time: duration | ||
| }); | ||
| } | ||
| } | ||
| const testResults = { | ||
| modules: { mathquill: moduleResults }, | ||
| passes: runner.stats.passes, | ||
| failures: runner.stats.failures, | ||
| skips: 0 | ||
| }; | ||
| if (json) window.testResultsString = JSON.stringify(testResults, null, 2); | ||
| else window.testResultsString = outputXML(testResults); | ||
| }); | ||
|
|
||
| const getTestSuiteTitle = (test) => xmlEscape(test.parent.fullTitle()); | ||
|
|
||
| // must escape a few symbols in xml attributes: | ||
| // http://stackoverflow.com/questions/866706/ | ||
| // which-characters-are-invalid-unless-encoded-in-an-xml-attribute | ||
| const xmlEscape = (string) => { | ||
| if (typeof string !== 'string') return ''; | ||
| string = string || ''; | ||
| string = string.replace(/&/g, '&'); | ||
| string = string.replace(/"/g, '"'); | ||
| string = string.replace(/</g, '<'); | ||
| return string; | ||
| }; | ||
| if (json) window.testResultsString = JSON.stringify(testResults, null, 2); | ||
| else window.testResultsString = outputXML(testResults); | ||
| }); | ||
|
|
||
| const getTestSuiteTitle = (test) => xmlEscape(test.parent.fullTitle()); | ||
|
|
||
| // must escape a few symbols in xml attributes: | ||
| // http://stackoverflow.com/questions/866706/ | ||
| // which-characters-are-invalid-unless-encoded-in-an-xml-attribute | ||
| const xmlEscape = (string) => { | ||
| if (typeof string !== 'string') return ''; | ||
| string = string || ''; | ||
| string = string.replace(/&/g, '&'); | ||
| string = string.replace(/"/g, '"'); | ||
| string = string.replace(/</g, '<'); | ||
| return string; | ||
| }; | ||
|
|
||
| const outputXML = (results) => { | ||
| const xml = []; | ||
| xml.push('<?xml version="1.0"?>'); | ||
| xml.push('<testsuites>'); | ||
|
|
||
| for (const moduleName in results.modules) { | ||
| const module = results.modules[moduleName]; | ||
| for (const test of module) { | ||
| xml.push(`<testsuite name="${moduleName}.${test.name}" time="${test.time}">`); | ||
|
|
||
| for (const assertion of test.assertions) { | ||
| const assertionMessage = assertion.message || 'no-assertion-message'; | ||
| const assertionTime = assertion.elapsedTime; | ||
|
|
||
| xml.push(`<testcase name="${assertionMessage}" time="${assertionTime}">`); | ||
|
|
||
| if (assertion.result === false) { | ||
| xml.push(`<failure message="${assertionMessage}">`); | ||
| xml.push(`Expected: ${assertion.expected}\n`); | ||
| xml.push(`Actual: ${assertion.actual}\n`); | ||
| xml.push(`Stacktrace: ${assertion.stacktrace}`); | ||
| xml.push('</failure>'); | ||
| } else if (assertion.result === undefined) { | ||
| xml.push('<skipped />'); | ||
|
|
||
| const outputXML = (results) => { | ||
| const xml = []; | ||
| xml.push('<?xml version="1.0"?>'); | ||
| xml.push('<testsuites>'); | ||
|
|
||
| for (const moduleName in results.modules) { | ||
| const module = results.modules[moduleName]; | ||
| for (const test of module) { | ||
| xml.push(`<testsuite name="${moduleName}.${test.name}" time="${test.time}">`); | ||
|
|
||
| for (const assertion of test.assertions) { | ||
| const assertionMessage = assertion.message || 'no-assertion-message'; | ||
| const assertionTime = assertion.elapsedTime; | ||
|
|
||
| xml.push(`<testcase name="${assertionMessage}" time="${assertionTime}">`); | ||
|
|
||
| if (assertion.result === false) { | ||
| xml.push(`<failure message="${assertionMessage}">`); | ||
| xml.push(`Expected: ${assertion.expected}\n`); | ||
| xml.push(`Actual: ${assertion.actual}\n`); | ||
| xml.push(`Stacktrace: ${assertion.stacktrace}`); | ||
| xml.push('</failure>'); | ||
| } else if (assertion.result === undefined) { | ||
| xml.push('<skipped />'); | ||
| } | ||
|
|
||
| xml.push('</testcase>'); | ||
| } | ||
|
|
||
| xml.push('</testcase>'); | ||
| xml.push('</testsuite>'); | ||
| } | ||
|
|
||
| xml.push('</testsuite>'); | ||
| } | ||
| } | ||
|
|
||
| return xml.join('\n'); | ||
| }; | ||
| } | ||
| return xml.join('\n'); | ||
| }; | ||
| } | ||
| }); | ||
| </script> | ||
| <!-- include the library with the tests inlined --> | ||
| <script id="mathquill" src="mathquill.test.js"></script> | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I said not to add these. In general,
input-test.htmlis set up to have the default options that are used by PG. The exception is the addition of thesubscriptbutton to demonstrate the usage of the theaddToolBarButtonsmethod, and don't entirely like that I did that. I was planning to eventually add a user interface element to the page to allow dynamically adding and removing buttons from the toolbar. I don't like these buttons that are non-standard being added to this.