Skip to content
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

zenn-markdown-html のテストで HTML 文字列どうしの比較を止める #434

Open
uttk-dev opened this issue Feb 21, 2023 · 4 comments

Comments

@uttk-dev
Copy link
Contributor

概要

zenn-markdown-html のテストでは、markdownToHtml() の出力結果をテストする際に HTML 文字列を直接比較している箇所があるが、これだと出力結果が少し変わっただけで大きな修正を必要とするし、コードが読みにくい。

そのため、node-html-parser などの HTML パーサーを使って出力された HTML 文字列をテストしたい。

@uttk-dev uttk-dev changed the title zenn-markdown-html のテストで html 文字列の比較を止める zenn-markdown-html のテストで HTML 文字列どうしの比較を止める Feb 21, 2023
@ysknsid25
Copy link
Contributor

@uttk-dev

このissueなのですが、以下のようなイメージということですよね?

packages/zenn-markdown-html/tests/basic.test.tsを例に。

import markdownToHtml from '../src/index';

const { parse } = require('node-html-parser');

describe('Convert markdown to html properly', () => {
  test('should convert markdown to html properly', () => {
    const html = markdownToHtml('Hello\n## hey\n\n- first\n- second\n');
    const parsedHtml = parse(html).toString();

    expect(parsedHtml).toContain(parse(`<p>Hello</p>`).toString());
    expect(parsedHtml).toContain(
      parse(`<h2 id="hey"><a class="header-anchor-link" href="#hey" aria-hidden="true"></a> hey</h2>`).toString()
    );
    expect(parsedHtml).toContain(parse(`<ul>\n<li>first</li>\n<li>second</li>\n</ul>\n`).toString());
  });
};

@uttk-dev
Copy link
Contributor Author

uttk-dev commented May 9, 2023

@ysknsid25

コメントありがとうございます。

実は既に使っているコードがいくつかありまして、そこを参考にされると良いかと思います。
packages/zenn-markdown-html/tests/basic.test.ts の場合ですと、私は以下のようなイメージでした 👇

import markdownToHtml from '../src/index';

import { parse } from 'node-html-parser';

describe('Convert markdown to html properly', () => {
  test('should convert markdown to html properly', () => {
    const parsedHtml = parse(
      markdownToHtml('Hello\n## hey\n\n- first\n- second\n')
    );

    // `<p>Hello</p>`
    expect(parsedHtml.querySelector('p')?.innerText).toContain('Hello');

    // `<h2 id="hey"><a class="header-anchor-link" href="#hey" aria-hidden="true"></a> hey</h2>`
    const h2 = parsedHtml.querySelector('h2#hey');
    expect(h2?.innerText).toBe(' hey');

    const anchor = h2?.querySelector('a.header-anchor-link');
    expect(anchor?.getAttribute('href')).toBe('#hey');
    expect(anchor?.getAttribute('aria-hidden')).toBe('true');

    // `<ul>\n<li>first</li>\n<li>second</li>\n</ul>`
    const ul = parsedHtml.querySelector('ul');
    const list = ul?.querySelectorAll('li');
    expect(list?.[0]?.innerText).toBe('first');
    expect(list?.[1]?.innerText).toBe('second');
  });

  // ...
});

ポイントとしては、セレクターを使うことで DOM 要素を取得するついでに簡単な属性の検証もやっています。

この比較の良い点は、

  • 文字列の比較よりプログラマブルなので共通化しやすい
  • テストを細分化しやすい
  • 多少の変更に強くなる( かも? )

などがあると思っています。

ただ現状だと共通化などしていないため、今のコードよりも記述量が多くなってしまったりするかもしれません。やるのであれば issue を切り崩して小さい単位( 例えば 1 ファイルずつとか )でやっていくのが良いかと思います。

P.S. これが最適解と言いたいわけではなく、他に良い案があれば受け付けていますので、お気軽にご意見下さい。

@ysknsid25
Copy link
Contributor

@uttk-dev

ご丁寧にご回答いただきありがとうございました!!
まずはおっしゃられたイメージで対応してみます!

@senkenn
Copy link
Contributor

senkenn commented Jul 24, 2024

@ysknsid25

コメントありがとうございます。

実は既に使っているコードがいくつかありまして、そこを参考にされると良いかと思います。 packages/zenn-markdown-html/tests/basic.test.ts の場合ですと、私は以下のようなイメージでした 👇

import markdownToHtml from '../src/index';

import { parse } from 'node-html-parser';

describe('Convert markdown to html properly', () => {
  test('should convert markdown to html properly', () => {
    const parsedHtml = parse(
      markdownToHtml('Hello\n## hey\n\n- first\n- second\n')
    );

    // `<p>Hello</p>`
    expect(parsedHtml.querySelector('p')?.innerText).toContain('Hello');

    // `<h2 id="hey"><a class="header-anchor-link" href="#hey" aria-hidden="true"></a> hey</h2>`
    const h2 = parsedHtml.querySelector('h2#hey');
    expect(h2?.innerText).toBe(' hey');

    const anchor = h2?.querySelector('a.header-anchor-link');
    expect(anchor?.getAttribute('href')).toBe('#hey');
    expect(anchor?.getAttribute('aria-hidden')).toBe('true');

    // `<ul>\n<li>first</li>\n<li>second</li>\n</ul>`
    const ul = parsedHtml.querySelector('ul');
    const list = ul?.querySelectorAll('li');
    expect(list?.[0]?.innerText).toBe('first');
    expect(list?.[1]?.innerText).toBe('second');
  });

  // ...
});

ポイントとしては、セレクターを使うことで DOM 要素を取得するついでに簡単な属性の検証もやっています。

この比較の良い点は、

  • 文字列の比較よりプログラマブルなので共通化しやすい
  • テストを細分化しやすい
  • 多少の変更に強くなる( かも? )

などがあると思っています。

ただ現状だと共通化などしていないため、今のコードよりも記述量が多くなってしまったりするかもしれません。やるのであれば issue を切り崩して小さい単位( 例えば 1 ファイルずつとか )でやっていくのが良いかと思います。

P.S. これが最適解と言いたいわけではなく、他に良い案があれば受け付けていますので、お気軽にご意見下さい。

試しにこちらで書いてみたのですが、以下の問題点がありました。

  • やはり記述量が多い(共通化もしにくそう)
  • 意図しない余計なタグ、属性が入ってしまった場合に気付きにくい
    • .getAttributesではなく.attrs などを使えば全ての属性を取得し.StrictEqual()などで検証できるが冗長になる
  • expectを書き忘れることがある(innerTextなど)

追記:とは思いましたが、単体テストとしてだと余計なタグや属性を省けるセレクターベースのほうが良い気もしてきました。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants