Rumah > hujung hadapan web > tutorial js > Belajar TDD dengan melakukan: Menandai ahli dalam Editor Teks Kaya Umbraco

Belajar TDD dengan melakukan: Menandai ahli dalam Editor Teks Kaya Umbraco

Barbara Streisand
Lepaskan: 2024-10-08 06:21:01
asal
912 orang telah melayarinya

Learning TDD by doing: Tagging members in Umbraco

Dalam sistem yang saya bina, saya memerlukan keupayaan untuk menyebut ahli Umbraco dalam teks dalam tapak web. Untuk melakukan itu, saya perlu membina sambungan kepada Editor Teks Kaya Umbraco: TinyMCE.

Konteks

Sebagai editor kandungan, saya ingin menandai ahli dalam mesej atau artikel supaya mereka dimaklumkan tentang kandungan baharu tentang mereka.

Saya melihat pelaksanaan yang serupa, seperti dalam Slack atau pada X. Slack menggunakan teg html khas untuk sebutan semasa menulis, tetapi kemudian menghantar data ke bahagian belakang dengan token dengan format tertentu. Saya memutuskan untuk mengambil pendekatan yang sama, tetapi buat masa ini lupakan tentang langkah terjemahan. Dalam kandungan, sebutan akan kelihatan seperti ini:


<mention user-id="1324" class="mceNonEditable">@D_Inventor</mention>


Salin selepas log masuk

Penerokaan awal

Sebelum saya mula membina, saya sedang mencari cara untuk menyambung ke TinyMCE di Umbraco. Ini adalah salah satu perkara paling saya gemari untuk dilanjutkan di pejabat belakang Umbraco. Saya telah melakukan ini sebelum ini, dan saya mendapati ia paling mudah untuk melanjutkan editor jika saya mencipta penghias pada tinyMceService Umbraco dalam AngularJS. Dalam dokumentasi TinyMCE, saya menemui ciri yang dipanggil 'autoCompleters', yang melakukan apa yang saya perlukan, jadi terdapat cangkuk saya ke dalam editor. Kod awal saya (tanpa sebarang ujian lagi), kelihatan seperti ini:


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<string, unknown>
      ): Promise<IMceAutocompleteItem[]>
        // 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;
}


Salin selepas log masuk

Saya menggunakan vite dan skrip taip dalam projek ini, tetapi saya tidak mempunyai sebarang jenis untuk TinyMCE dipasang. Buat masa ini saya akan menyimpan apa-apa dan hanya cuba mengelakkan TinyMCE sebanyak mungkin.

Membina dengan TDD

Saya memutuskan untuk menggunakan jest untuk ujian. Saya dapati permulaan yang mudah dan saya berjaya dengan cepat membuat sesuatu berfungsi.

✅ Success
I learned a new tool for unit testing in frontend code. I succesfully applied the tool to write a frontend with unit tests

Saya menulis ujian pertama saya:

mention-manager.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);
  });
});


Salin selepas log masuk

Saya agak terkejut dengan ketegasan penyusun skrip taip. Bekerja dalam langkah-langkah di sini benar-benar bermakna tidak menambah apa-apa yang sebenarnya anda tidak gunakan lagi. Sebagai contoh, saya ingin menambah rujukan kepada "UI", kerana saya tahu saya akan menggunakannya kemudian, tetapi saya sebenarnya tidak dapat menyusun MentionsManager sehingga saya menggunakan semua yang saya masukkan dalam pembina.

Selepas beberapa pusingan merah, hijau dan refactor, saya berakhir dengan ujian ini:

mention-manager.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);
  });
});


Salin selepas log masuk

Dengan adanya logik ini, saya boleh mengambil sebutan daripada mana-mana sumber dan menunjukkannya dalam RTE melalui cangkuk 'fetch'.
Saya menggunakan pendekatan yang sama untuk mencipta kaedah 'pilih' untuk mengambil ahli yang dipilih dan memasukkan sebutan ke dalam editor. Ini ialah kod yang saya dapat:

mention-manager.ts


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

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

  async fetch(take: number, query?: string): Promise<IMention[]> {
    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);
  }
}


Salin selepas log masuk
❓ Uncertainty
The Range interface is a built-in type that is really difficult to mock and this interface leaks an implementation detail into my business logic. I feel like there might've been a better way to do this.

Tinjau kembali

Secara keseluruhan, saya rasa saya mendapat kod ringkas yang mudah diubah. Masih terdapat bahagian kod ini yang saya tidak begitu suka. Saya mahu logik perniagaan memacu UI, tetapi kod itu berakhir lebih seperti kedai ringkas yang juga melakukan satu panggilan ke UI. Saya tertanya-tanya jika saya boleh membungkus UI dengan lebih kuat untuk memanfaatkan pengurus dengan lebih baik.

Atas ialah kandungan terperinci Belajar TDD dengan melakukan: Menandai ahli dalam Editor Teks Kaya Umbraco. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

sumber:dev.to
Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn
Artikel terbaru oleh pengarang
Tutorial Popular
Lagi>
Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan