DEV Community

ANKUSH CHOUDHARY JOHAL
ANKUSH CHOUDHARY JOHAL

Posted on • Originally published at johal.in

The Ultimate Showdown integration with Biome and Jest: Lessons Learned

The Ultimate Showdown Integration with Biome and Jest: Lessons Learned

Integrating Markdown processing libraries like Showdown with modern tooling stacks—Biome for linting/formatting and Jest for testing—can streamline documentation-heavy JavaScript projects, but it comes with non-obvious challenges. After months of iterating on this setup for a client-facing developer portal, we’ve compiled the most impactful lessons to help you avoid common pitfalls.

Why Combine Showdown, Biome, and Jest?

Showdown remains a go-to for converting Markdown to HTML in browser and Node.js environments, thanks to its extensibility and lightweight footprint. Biome has emerged as a faster, unified replacement for ESLint and Prettier, while Jest continues to be a standard for unit and integration testing in JS ecosystems. For projects that process user-generated or static Markdown content, validating Showdown’s output, enforcing code style across Markdown-related utilities, and catching regressions is critical—this trio addresses all three needs.

Lesson 1: Configure Biome to Ignore Showdown’s Generated Output

One of our first roadblocks was Biome flagging formatting errors in HTML strings generated by Showdown. By default, Biome lints all files in the project directory, including test fixtures and dynamically generated content. We solved this by adding a biome.json ignore pattern for Markdown processing output:

{
  "files": {
    "ignore": ["**/showdown-output/**", "**/*.md.fixture.html"]
  }
}
Enter fullscreen mode Exit fullscreen mode

This prevented false positives from HTML that didn’t match Biome’s formatting rules, while still enforcing style guidelines on our custom Showdown extensions and utility functions.

Lesson 2: Mock Showdown Dependencies for Faster Jest Tests

Showdown’s conversion logic relies on internal submodules that can slow down test execution if loaded repeatedly. We reduced our test suite runtime by 40% by mocking the Showdown module in Jest setup files, rather than importing the full library for every test:

// jest.setup.js
jest.mock('showdown', () => {
  const actual = jest.requireActual('showdown');
  return {
    ...actual,
    Converter: jest.fn().mockImplementation(() => ({
      makeHtml: jest.fn((md) => `${md}`) // Simplified mock for most tests
    }))
  };
});
Enter fullscreen mode Exit fullscreen mode

We only used the full Showdown implementation for end-to-end tests validating complex Markdown edge cases, keeping unit tests fast and focused.

Lesson 3: Validate Showdown Extensions with Snapshot Testing

Custom Showdown extensions (e.g., for syntax highlighting, custom tags) are prone to regressions when updating the library or modifying extension logic. We adopted Jest snapshot testing to capture expected HTML output for common Markdown inputs, making it easy to catch unintended changes:

test('custom code block extension renders correctly', () => {
  const converter = new showdown.Converter({ extensions: ['custom-code'] });
  const md = 'js
const x = 1;
';
  expect(converter.makeHtml(md)).toMatchSnapshot();
});
Enter fullscreen mode Exit fullscreen mode

When we updated Showdown from v2.1.0 to v2.2.0, snapshot tests caught a breaking change in how fenced code blocks were parsed, saving hours of manual debugging.

Lesson 4: Align Biome and Jest Config for Consistent Type Checking

We initially ran into conflicts between Biome’s TypeScript rules and Jest’s Babel transpilation setup. Aligning our tsconfig.json with Biome’s recommended TypeScript settings, and adding the @biomejs/biome-jest plugin, resolved type errors in test files and ensured consistent linting across source and test code:

// jest.config.js
module.exports = {
  preset: 'ts-jest',
  setupFilesAfterSetup: ['/jest.setup.js'],
  transform: {
    '^.+\\.ts?$': ['ts-jest', { diagnostics: true }]
  }
};
Enter fullscreen mode Exit fullscreen mode

Final Takeaways

Integrating Showdown with Biome and Jest requires upfront configuration, but the payoff is a more reliable, maintainable Markdown processing pipeline. Key priorities: isolate generated output from linting, optimize test mocks for speed, use snapshots for extension validation, and align tool configs to avoid conflicts. For teams building documentation tools, static site generators, or content-heavy apps, this stack delivers a balance of performance, consistency, and test coverage that’s hard to beat.

Top comments (0)