diff --git a/package.json b/package.json index e02d334..9b05c74 100644 --- a/package.json +++ b/package.json @@ -52,6 +52,7 @@ "@types/fs-extra": "^9.0.13", "@types/jest": "^27.0.2", "@types/json2csv": "^5.0.3", + "@types/markdown-table": "^2.0.0", "@types/node": "^16.10.2", "@types/prettier": "^2.4.1", "@typescript-eslint/eslint-plugin": "^4.32.0", @@ -76,6 +77,7 @@ "fs-extra": "^10.0.0", "json2csv": "^5.0.6", "kleur": "^4.1.4", - "log-update": "^4.0.0" + "log-update": "^4.0.0", + "markdown-table": "^2.0.0" } } diff --git a/src/internal/common-types.ts b/src/internal/common-types.ts index 0042820..753b06b 100644 --- a/src/internal/common-types.ts +++ b/src/internal/common-types.ts @@ -84,7 +84,7 @@ export type SaveOptions = { * * @default 'json' */ - format?: 'json' | 'csv' | 'table.html' | 'chart.html' + format?: 'json' | 'csv' | 'table.html' | 'chart.html' | 'table.md' } export type CaseResult = { diff --git a/src/internal/prepareFileContent.ts b/src/internal/prepareFileContent.ts index 78db3fa..7d5c3dc 100644 --- a/src/internal/prepareFileContent.ts +++ b/src/internal/prepareFileContent.ts @@ -1,7 +1,8 @@ import { method, multi } from '@arrows/multimethod' import { parse } from 'json2csv' import { CaseResultWithDiff, SaveOptions, Summary } from './common-types' -import { stripIndent, html } from 'common-tags' +import { stripIndent, html, stripIndents } from 'common-tags' +import * as markdownTable from 'markdown-table' const flattenResults = (results: CaseResultWithDiff[]) => { return results.map((result) => ({ @@ -102,6 +103,28 @@ const prepareHTMLTable = (summary: Summary, options: SaveOptions) => { return stripIndent(markup) } +const prepareMarkdownTable = (summary: Summary, options: SaveOptions) => { + const results = options.details + ? flattenResults(summary.results) + : summary.results.map(({ name, ops, margin, percentSlower }) => { + return { name, ops, margin, percentSlower } + }) + + const headers = Object.keys(results[0]) + const tableBody: string[][] = results.map((result) => { + // @ts-ignore + return headers.map((key: string) => (String(result[key]))) + }) + + return stripIndents`**${summary.name}:** + + ${markdownTable([ + headers, + ...tableBody + ])} + ` +} + const prepareColors = (percents: number[]) => { return percents.map((percent) => { const hue = 120 * ((100 - percent) / 100) @@ -242,6 +265,7 @@ const prepareFileContent = multi( method('csv', prepareCSV), method('table.html', prepareHTMLTable), method('chart.html', prepareHTMLChart), + method('table.md', prepareMarkdownTable), method(prepareJSON), ) diff --git a/src/suite.test.ts b/src/suite.test.ts index 925e1ee..5524966 100644 --- a/src/suite.test.ts +++ b/src/suite.test.ts @@ -800,6 +800,88 @@ describe('suite', () => { TIMEOUT, ) + it( + 'Correctly saves simple Markdown table', + async () => { + await suite( + 'Example 17', + + add( + 'First', + () => { + return () => [1, 2, 3, 4, 5].reduce((a, b) => a + b) + }, + { maxTime: 0.01 }, + ), + + add( + 'Second', + () => { + return () => [1, 2].reduce((a, b) => a + b) + }, + { maxTime: 0.01 }, + ), + + save({ format: 'table.md' }), + ) + + await delay(1000) + + const file = fs.readdirSync('benchmark/results')[0] + + const content = fs.readFileSync(`benchmark/results/${file}`).toString() + + const lineSplit = content.split('\n') + + expect(lineSplit[0]).toMatch(/.*(Example 17).*$/) + expect(lineSplit[2]).toMatch(/.*(name).*(ops).*(margin).*(percentSlower).*$/) + expect(lineSplit[4]).toMatch(/.*(First).*$/) + expect(lineSplit[5]).toMatch(/.*(Second).*$/) + }, + TIMEOUT, + ) + + it( + 'Correctly saves detailed Markdown table', + async () => { + await suite( + 'Example 18', + + add( + 'First', + () => { + return () => [1, 2, 3, 4, 5].reduce((a, b) => a + b) + }, + { maxTime: 0.01 }, + ), + + add( + 'Second', + () => { + return () => [1, 2].reduce((a, b) => a + b) + }, + { maxTime: 0.01 }, + ), + + save({ format: 'table.md', details: true }), + ) + + await delay(1000) + + const file = fs.readdirSync('benchmark/results')[0] + + const content = fs.readFileSync(`benchmark/results/${file}`).toString() + + const lineSplit = content.split('\n') + + expect(lineSplit[0]).toMatch(/.*(Example 18).*$/) + expect(lineSplit[2]).toMatch(/.*(name).*(ops).*(margin).*(percentSlower).*(samples).*(promise).*(min).*(max).*(mean).*(median).*(standardDeviation).*(marginOfError).*(standardErrorOfMean).*(sampleVariance).*$/) + expect(lineSplit[4]).toMatch(/.*(First).*$/) + expect(lineSplit[5]).toMatch(/.*(Second).*$/) + }, + TIMEOUT, + ) + it( 'Rounds results to smallest distinctive precision', async () => {