Jest Markdown Pipeline
"Nothing is better than documentation with examples. But nothing is worse than examples that don't work because the code has changed since the documentation was written." - rustbook
Example code blocks in our markdown or inline documentation comments can be useful to quickly demonstrate how one can use our software. As they are part of our living standards, each example code should be functional code that can be asserted and tested. Documentation example code should be automated, tested and linted as part of our workflow.
Initially, we were thinking of creating a md-jest
for parsing code blocks in markdown and transforming them into
jest tests. Similar to how ts-jest
transform TS to CommonJS, but using contented-processor
to transform MD files.
@eli-lim suggested we transform jest files *.test.ts
into Markdown instead. We
get the DX of writing test with Jest and IDE support (without having to support write our own runner). It is much
easier to transform comments to markdown than transform markdown to code (although not much harder, the focus here is
on the DX). Further, you get the natural flow of writing narrative and writing tests as a narrative.
This page, is written in a jest test file.
JestMarkdown.spec.ts
Comments Parsing
All comments are automatically picked up as Markdown with indent stripped. Indent are stripped using
strip-indent
, *
are also stripped. For bullet points, you should use -
and avoid using *
to prevent
unintentional stripping.
//
- Line Comment/*
- Block Comment/**
- Block Comment
This section is generated by the code snippet below.
This is a multi line with *
stripped from each line.
This is a Line Comment
This is a Block Comment
This is a Multi Line
Block Comment
without *
.
/**
* ### This section is generated by the code snippet below.
*
* This is a multi line with `*` stripped from each line.
*/
// This is a `Line Comment`
/* This is a `Block Comment` */
/* This is a `Multi Line`
`Block Comment` without `*`. */
Including Codeblocks
JestMarkdown
has the ability to "pickup" codes and add them into a codeblock. Codeblock is parsed line by line,
@contented codeblock:start
indicate the starting line and @contented codeblock:end
indicate the ending line.
Everything between will be included into a codeblock. Although not recommended, you can nest multiple
@contented codeblock
between.
'@contented codeblock:start',
'@contented codeblock:end',
it('this it statement is in a codeblock with nested codeblock', () => {
const symbols = [
// @contented codeblock:start
'@contented codeblock:start',
// @contented codeblock:end
'everything in between will be included as a TypeScript codeblock ```ts\n${codes}\n```',
// @contented codeblock:start
'@contented codeblock:end',
// @contented codeblock:end
];
expect(join(...symbols)).toBeDefined();
});
Beta Pipeline
This Pipeline is currently in Beta!
This pipeline is considered Beta, while the idea and the intent will stay intact. We want to optimize this
pipeline for better integration with Jest. Better integration with Jest Semantic describe
, it
, before
, and
after
; to achieve a more natural authoring process.
Imagine the below:
describe('MyAPI: Javascript Client', () => {
const api = new MyApi('https://my-api.com');
describe('GetRecords', () => {
it('Example', function () {
const records = api.GetRecords(10);
});
});
describe('PutRecord', () => {
it('Example', async function () {
await api.PutRecord({
text: 'MyText',
});
});
});
});
Should generate this Markdown:
MyAPI: Javascript Client
const api = new MyApi('https://my-api.com');
GetRecords
Example
const records = api.GetRecords(10);
PutRecord
Example
await api.PutRecord({
text: 'MyText',
});