「労働者が自分の仕事をうまくやりたいなら、まず自分の道具を研ぎ澄まさなければなりません。」 - 孔子、「論語。陸霊公」
表紙 > プログラミング > TDD の学習: Umbraco のリッチ テキスト エディターでメンバーにタグ付けする

TDD の学習: Umbraco のリッチ テキスト エディターでメンバーにタグ付けする

2024 年 11 月 2 日に公開
ブラウズ:957

Learning TDD by doing: Tagging members in Umbraco

私が構築しているシステムでは、Web サイト内のテキストで Umbraco メンバーに言及する機能が必要です。そのためには、Umbraco のリッチ テキスト エディターの拡張機能である TinyMCE.

を構築する必要があります。

コンテクスト

コンテンツ編集者として、メッセージまたは記事内でメンバーにタグを付けて、メンバーに関する新しいコンテンツに関する通知を受信できるようにしたいと考えています。

Slack や X などの同様の実装を調べました。Slack は書き込み中のメンションに特別な HTML タグを使用しますが、その後、特定の形式のトークンを使用してデータをバックエンドに送信します。私も同様のアプローチを取ることにしましたが、今のところは翻訳ステップのことは忘れてください。コンテンツでは、メンションは次のようになります:


@D_Inventor

初期の探索

構築を始める前に、Umbraco で TinyMCE に接続する方法を探していました。これは、Umbraco バックオフィスで拡張したくないものの 1 つです。ただし、以前にこれを実行したことがあります。AngularJS で Umbraco の tinyMceService にデコレーターを作成すると、エディターを拡張するのが最も簡単であることがわかりました。 TinyMCE のドキュメントで、「autoCompleters」と呼ばれる機能を見つけました。これはまさに私が必要なことを実行するものでした。そこで、エディターにフックを取り付けました。私の最初のコード (まだテストなし) は次のようになります:


rtedecorator.$inject = ["$delegate"];
export function rtedecorator($delegate: any) {
  const original = $delegate.initializeEditor;

  $delegate.initializeEditor = function (args: any) {
    original.apply($delegate, arguments);

    args.editor.contentStyles.push("mention { background-color: #f7f3c1; }");
    args.editor.ui.registry.addAutocompleter("mentions", {
      trigger: "@",
      fetch: (
        pattern: string,
        maxResults: number,
        _fetchOptions: Record
      ): Promise
        // TODO: fetch from backend
        => Promise.resolve([{ type: "autocompleteitem", value: "1234", text: "D_Inventor" }]),
      onAction: (api: any, rng: Range, value: string): void => {
        // TODO: business logic
        api.hide();
      },
    });
  };

  return $delegate;
}


このプロジェクトでは vite と typescript を使用していますが、TinyMCE のタイプがインストールされていません。今のところ、私はすべてを保持し、TinyMCE をできるだけ避けるようにします。

TDD を使用した構築

テストのために jest を使用することにしました。簡単に始めることができ、すぐに何かを動作させることができました。

✅ 成功
フロントエンド コードの単体テストのための新しいツールを学びました。ツールを適用して単体テストを含むフロントエンドを作成することに成功しました

最初のテストを書きました:

メンションマネージャー.test.ts


describe("MentionsManager.fetch", () => {
  let sut: MentionsManager;
  let items: IMention[];

  beforeEach(() => {
    items = [];
    sut = new MentionsManager();
  });

  test("should be able to fetch one result", async () => {
    items.push({ userId: "1234", userName: "D_Inventor" });
    const result = await sut.fetch(1);
    expect(result).toHaveLength(1);
  });
});


typescript コンパイラの厳密さには少々驚きました。ここで段階的に作業するということは、実際には、まだ実際に使用していないものを追加しないことを意味します。たとえば、「UI」への参照を追加したいと思ったのは、それを後で使用することがわかっていたからですが、コンストラクターに入力したものをすべて使用するまで、MentionsManager を実際にコンパイルすることはできませんでした。

赤、緑、リファクタリングを数ラウンド行った後、次のテストが完成しました:

メンションマネージャー.test.ts


describe("MentionsManager.fetch", () => {
  let sut: MentionsManager;
  let items: IMention[];

  beforeEach(() => {
    items = [];
    sut = new MentionsManager(() => Promise.resolve(items));
  });

  test("should be able to fetch one result", async () => {
    items.push({ userId: "1234", userName: "D_Inventor" });
    const result = await sut.fetch(1);
    expect(result).toHaveLength(1);
  });

  test("should be able to fetch empty result", async () => {
    const result = await sut.fetch(1);
    expect(result).toHaveLength(0);
  });

  test("should be able to fetch many results", async () => {
    items.push({ userId: "1324", userName: "D_Inventor" }, { userId: "3456", userName: "D_Inventor2" });
    const result = await sut.fetch(2);
    expect(result).toHaveLength(2);
  });

  test("should return empty list upon error", () => {
    const sut = new MentionsManager(() => {
      throw new Error("Something went wrong while fetching");
    }, {} as IMentionsUI);
    return expect(sut.fetch(1)).resolves.toHaveLength(0);
  });
});


このロジックを導入すると、任意のソースからメンションをフェッチし、「フェッチ」フックを通じて RTE に表示できます。
同じアプローチを使用して、選択したメンバーを取得し、エディターにメンションを挿入する「pick」メソッドを作成しました。これは私が最終的に得たコードです:

メンションマネージャー.ts


export class MentionsManager {
  private mentions: IMention[] = [];

  constructor(
    private source: MentionsAPI,
    private ui: IMentionsUI
  ) {}

  async fetch(take: number, query?: string): Promise {
    try {
      const result = await this.source(take, query);
      if (result.length === 0) return [];
      this.mentions = result;

      return result;
    } catch {
      return [];
    }
  }

  pick(id: string, location: Range): void {
    const mention = this.mentions.find((m) => m.userId === id);
    if (!mention) return;

    this.ui.insertMention(mention, location);
  }
}


❓ 不確実性
Range インターフェイスは組み込み型であり、モックするのは非常に困難であり、このインターフェイスは実装の詳細をビジネス ロジックに漏洩させます。もっと良い方法があったような気がします。

振り返り

全体的には、変更が簡単なシンプルなコードになったと思います。このコードにはまだ気に入らない部分があります。ビジネス ロジックで UI を駆動したいと考えていましたが、コードは UI への呼び出しを 1 回行う単純なストアのようになりました。マネージャーをもっと活用するために、UI をもっと強力にラップできないだろうか。

リリースステートメント この記事は次の場所に転載されています: https://dev.to/d_inventor/learning-tdd-by-doing-tagging-members-in-umbracos-rich-text-editor-29o4?1 侵害がある場合は、study_golang にご連絡ください。 @163.com 削除
最新のチュートリアル もっと>
  • 項目 他の型の方が適している場合は文字列を避ける
    項目 他の型の方が適している場合は文字列を避ける
    1.他のデータ型の代わりに文字列を使用することは避けてください: 文字列はテキストを表すように設計されていますが、数値、列挙型、または集合構造を表すために誤用されることがよくあります。 データが本質的に数値である場合は、String. ではなく、int、float、BigInteger などの型を...
    プログラミング 2024 年 11 月 2 日に公開
  • sync.WaitGroup を使用して Go 同時実行でデッドロックを防ぐ方法
    sync.WaitGroup を使用して Go 同時実行でデッドロックを防ぐ方法
    ゴルーチンのデッドロックの解決このシナリオでは、Go 同時実行コードでデッドロック エラーが発生しました。問題を詳しく調べて、効率的な解決策を提供しましょう。このエラーは、プロデューサとコンシューマの動作の不一致が原因で発生します。プロデューサー関数に実装されたプロデューサーは、限られた期間、チャネ...
    プログラミング 2024 年 11 月 2 日に公開
  • テキスト ファイル内の Unicode テキストを処理する方法: エラーのない書き込みのための完全ガイド
    テキスト ファイル内の Unicode テキストを処理する方法: エラーのない書き込みのための完全ガイド
    テキスト ファイル内の Unicode テキスト: エラーのない記述のための包括的なガイドGoogle ドキュメントから抽出されたデータのコーディングは、特に困難な場合があります。 HTML で使用するために変換する必要がある非 ASCII シンボルが見つかった場合。このガイドでは、Unicode ...
    プログラミング 2024 年 11 月 2 日に公開
  • EchoAPI と不眠症: 実践例による包括的な比較
    EchoAPI と不眠症: 実践例による包括的な比較
    フルスタック開発者として、私は API のデバッグ、テスト、文書化のための一流のツールを用意することがいかに重要であるかを知っています。 EchoAPI と Insomnia は 2 つの傑出したオプションであり、それぞれに独自の特徴と機能があります。これらのツールについて説明し、その機能と利点を比...
    プログラミング 2024 年 11 月 2 日に公開
  • 移動時間と所要時間 |プログラミングチュートリアル
    移動時間と所要時間 |プログラミングチュートリアル
    導入 このラボは、Go の時間と期間のサポートについての理解をテストすることを目的としています。 時間 以下のコードには、Go で時間と期間を操作する方法の例が含まれています。ただし、コードの一部が欠落しています。あなたの仕事は、コードを完成させて期待通りに動作させ...
    プログラミング 2024 年 11 月 2 日に公開
  • ホイスティングにおける面接の質問と回答
    ホイスティングにおける面接の質問と回答
    1. JavaScript におけるホイスティングとは何ですか? 答え: ホイスティングは、変数や関数にメモリが割り当てられる実行コンテキストの作成フェーズ中のプロセスです。このプロセス中に、変数用のメモリが割り当てられ、変数には未定義の値が割り当てられます。関数の場合、関数定義全...
    プログラミング 2024 年 11 月 2 日に公開
  • JavaScript のドキュメント オブジェクト モデル (DOM) を理解する
    JavaScript のドキュメント オブジェクト モデル (DOM) を理解する
    こんにちは、素晴らしい JavaScript 開発者の皆さん? ブラウザは、スクリプト (特に JavaScript) が Web ページのレイアウトと対話できるようにするドキュメント オブジェクト モデル (DOM) と呼ばれるプログラミング インターフェイスを提供します。 We...
    プログラミング 2024 年 11 月 2 日に公開
  • SPRING BATCH でプログラミングを始める
    SPRING BATCH でプログラミングを始める
    Introduction Dans vos projets personnels ou professionnels, Il vous arrive de faire des traitements sur de gros volumes de données. Le traite...
    プログラミング 2024 年 11 月 2 日に公開
  • CSS で Github プロフィールを目立たせる
    CSS で Github プロフィールを目立たせる
    これまで、Github プロフィールをカスタマイズできる唯一の方法は、写真を更新するか名前を変更することでした。これは、すべての Github プロファイルが同じに見え、カスタマイズしたり目立たせるためのオプションが最小限であることを意味しました。 それ以来、Markdown を使用してカスタム セ...
    プログラミング 2024 年 11 月 2 日に公開
  • TypeScript ユーティリティの種類: コードの再利用性の向上
    TypeScript ユーティリティの種類: コードの再利用性の向上
    TypeScript は、開発者が型を効果的に変換および再利用できるようにする組み込みのユーティリティ型を提供し、コードをより柔軟で ​​DRY にします。この記事では、TypeScript スキルを次のレベルに引き上げるのに役立つ、Partial、Pick、Omit、Record などの主要なユー...
    プログラミング 2024 年 11 月 2 日に公開
  • 電報 window.open(url, &#_blank&#); iOSでは動作がおかしい
    電報 window.open(url, &#_blank&#); iOSでは動作がおかしい
    電報ボットを作成していて、ミニアプリからチャットに情報を転送するオプションを追加したいと考えています。 window.open(url, '_blank'); を使用することにしました。 iPhone で試してみるまでは問題なく動作していました。転送の代わりに、Share を取得しま...
    プログラミング 2024 年 11 月 2 日に公開
  • フロントエンド開発者とは誰ですか?
    フロントエンド開発者とは誰ですか?
    今日のインターネット上のすべての Web サイトやプラットフォームのユーザー インターフェイス部分は、フロントエンド開発者の仕事の成果です。彼らはユーザーフレンドリーなインターフェイスの作成に携わり、サイトの外観と機能を保証します。しかし、フロントエンド開発者とはいったい誰なのでしょうか?簡単に説明...
    プログラミング 2024 年 11 月 2 日に公開
  • CSS スタイルを保持したまま HTML コンテンツを PDF として保存するにはどうすればよいですか?
    CSS スタイルを保持したまま HTML コンテンツを PDF として保存するにはどうすればよいですか?
    CSS を含む HTML コンテンツを PDF として保存するWeb 開発では、コンテンツを別の形式にエクスポートする場合でも、見た目の美しさを維持することが非常に重要です。変換プロセス中に CSS スタイルが失われる可能性があるため、HTML 要素を PDF として保存しようとするときに問題が発生...
    プログラミング 2024 年 11 月 2 日に公開
  • Print_r() の使用時にファントム プロパティが DateTime オブジェクトに追加されるのはなぜですか?
    Print_r() の使用時にファントム プロパティが DateTime オブジェクトに追加されるのはなぜですか?
    Print_r() DateTime オブジェクトを変更しますPrint_r() は、DateTime オブジェクトにプロパティを追加し、デバッグ中のイントロスペクションを有効にします。この動作は、PHP 5.3 で導入された内部機能の副作用であり、テキストにダンプされたインスタンスにファントム パ...
    プログラミング 2024 年 11 月 2 日に公開
  • C のデータ構造とアルゴリズム: 初心者に優しいアプローチ
    C のデータ構造とアルゴリズム: 初心者に優しいアプローチ
    C では、データ構造とアルゴリズムを使用してデータを整理、保存、操作します。データ構造: 配列: 順序付けされたコレクション、インデックスを使用して要素にアクセスする リンク リスト: ポインターを介して要素をリンク、動的長さをサポート スタック: 先入れ後出し (FILO) 原則キュー: 先入れ先...
    プログラミング 2024 年 11 月 2 日に公開

免責事項: 提供されるすべてのリソースの一部はインターネットからのものです。お客様の著作権またはその他の権利および利益の侵害がある場合は、詳細な理由を説明し、著作権または権利および利益の証拠を提出して、電子メール [email protected] に送信してください。 できるだけ早く対応させていただきます。

Copyright© 2022 湘ICP备2022001581号-3