This module contains tests from CommonMark test suite to verify that the parser is working correctly.
import { StyledElement } from 'litscript/lib/src/custom-elem'
import { elem, text, highlightWs } from './helpers'
import { appendMarkdown } from './parser'
import './commonmark.css'
let loaded = import('./spec.json')
We read the CommonMark test cases from a JSON file. Its structure is defined below (unused properties are omitted).
interface CommonMarkTest {
markdown: string
html: string
example: number
section: string
}
let tests: CommonMarkTest[]
let succeeded = 0
let failed = 0
let totalDuration = 0
We define a custom element that can be used run tests specified in the
examples
attribute. It has format 1,3-5
where you can specify individual
tests separated by commas, or range of tests separated by dash.
export class CommonMarkRunner extends StyledElement {
static get observedAttributes(): string[] {
return ["examples"]
}
constructor() {
super('commonmark')
}
protected override connect() {
this.runExamples()
}
private get examples(): number[] {
let res: number[] = []
let examples = this.getAttribute("examples")
if (examples) {
let splitter = /\s*(?<sep>[,\-])?\s*(?<num>\d+)/g
let prev: number | undefined
let match: RegExpExecArray | null
while (match = splitter.exec(examples)) {
let { sep, num } = match.groups!
let curr = Number.parseInt(num)
if (prev && sep == "-")
for (let i = prev + 1; i < curr; ++i)
res.push(i)
res.push(curr)
prev = curr
}
}
return res
}
private async runExamples() {
if (!tests)
tests = await loaded
this.examples.forEach(num => this.runTest(tests[num - 1]))
}
private runTest(test: CommonMarkTest) {
let duration = 0
let result = "<<Not run>>"
try {
let root = elem('div')
let start = window.performance.now()
appendMarkdown(test.markdown, root)
duration = window.performance.now() - start
result = root.innerHTML
}
catch (e) {
if (e instanceof Error)
result = e.message + "\n" + e.stack
}
let pass = result == test.html
if (pass)
succeeded++
else
failed++
totalDuration += duration
this.renderTest(test, result, pass, duration)
}
private renderTest(test: CommonMarkTest, result: string, pass: boolean,
duration: number) {
let passcell = elem('th', text(pass ? "PASS" : "FAIL"))
passcell.className = pass ? "pass" : "fail"
this.body.append(elem('table',
elem('tr',
elem('th', text(`Example: ${test.example}`)),
elem('th', text(test.section)),
passcell),
elem('tr',
elem('th', text("Input")),
elem('th', text("Expected")),
elem('th', text("Actual"))),
elem('tr',
elem('td', elem('pre', elem('code',
...highlightWs(test.markdown)))),
elem('td', elem('pre', elem('code', ...highlightWs(test.html)))),
elem('td', elem('pre', elem('code', ...highlightWs(result))))),
elem('tr',
elem('td', text(`In ${duration.toFixed(1)}ms`)))))
}
}
export class CommonMarkSummary extends StyledElement {
constructor() {
super('commonmark')
}
protected override connect() {
window.requestIdleCallback(() => this.render())
}
private render() {
let count = succeeded + failed
this.body.append(elem('table',
elem('tr',
elem('th', text("Tests Run")),
elem('th', text("Succeeded")),
elem('th', text("Failed")),
elem('th', text("CommonMark Coverage"))),
elem('tr',
elem('td', text(count.toString())),
elem('td', text(succeeded.toString())),
elem('td', text(failed ? failed.toString() : "-")),
elem('td', text((count * 100 / 652).toFixed(1) + "%"))),
elem('tr',
elem('td', text(`In ${totalDuration.toFixed(1)}ms`)))))
}
}
customElements.define("commonmark-runner", CommonMarkRunner)
customElements.define("commonmark-summary", CommonMarkSummary)