Кроссфреймовая библиотека веб-компонентов 📚 с использованием Lit (часть II)


Тестирование

После того, как мы завершили работу над нашим компонентом карты, пришло время протестировать его. Я использовал пакет тестирования от Open Web Components, а документацию вы можете найти здесь в сочетании с jasmine и karma.

Мы начинаем описывать, какой компонент будет тестироваться, и определяем, что мы будем высмеивать в качестве свойств компонента:

import { Card } from './card';

describe('Card Component', () => {
    let el: Card;

    const card = {
        altText: 'Je suis a image',
        ctaText: 'Click me',
        image: 'http://example.com/image/',
        link: 'http://example.com/link/',
        text: 'amazing text',
        textDesc: 'other amazing text for test',
        textDescLink: 'http://example.com/author/',
        title: 'amazing title',
    };

}

Вход в полноэкранный режим Выйти из полноэкранного режима

После этого, перед запуском теста, мы загружаем фикстуру, которая будет передавать компонент Card с нашей пользовательской конфигурацией, и проверяем, определен ли элемент, проверяя instanceOf:

...

import { assert, expect, fixture, html } from '@open-wc/testing';

describe('Card Component', () => {
    ...

    beforeEach(async () => {
        el = await fixture<Card>(html` <card-image .card=${card}></card-image> `);
    });

    it('is defined', () => {
        assert.instanceOf(el, Card);
    });

}

Вход в полноэкранный режим Выйти из полноэкранного режима

Если все настроено правильно, мы запускаем тест, и у нас должен быть один успешный тест:

Давайте немного подробнее рассмотрим этот компонент:

...

describe('Card Component', () => {
      ...

      it('renders the image', () => {
        const image = el.shadowRoot?.querySelector('img');
        expect(image).to.exist;
        expect(image?.alt).to.equal(card.altText);
        expect(image?.src).to.equal(card.image);
      });

      it('renders the title', () => {
        const title = el.shadowRoot?.querySelector('#card-link');
        expect(title).to.exist;
        expect(title?.getAttribute('href')).to.equal(card.link);
        expect(title?.textContent).to.equal(card.title);
      });

      it('renders the text', () => {
        const text = el.shadowRoot?.querySelector('p');
        expect(text).to.exist;
        expect(text?.textContent).to.equal(card.text);
      });

      it('renders the cta text', () => {
        const ctaText = el.shadowRoot?.querySelector('.cta a');
        expect(ctaText).to.exist;
        expect(ctaText?.textContent).to.equal(card.ctaText);
      });

      it('renders the description link', () => {
        const textDesc = el.shadowRoot?.querySelector('small a');
        expect(textDesc).to.exist;
        expect(textDesc?.getAttribute('href')).to.equal(card.textDescLink);
        expect(textDesc?.textContent).to.equal(card.textDesc);
      });

      it('dispatch the mousedown event', () => {
        el.mouseDown();
        expect(el.down).to.be.a('number');
      });

}

Вход в полноэкранный режим Выход из полноэкранного режима

Это должно увеличить покрытие до более чем 80%.

Компонент карточек

Мы будем делать второй компонент, в котором мы можем передавать конфигурацию, чтобы иметь несколько карточек.
Это открывает возможность повторно использовать один внутренний компонент и делать другой с другими целями, которые могут иметь другую конфигурацию. Также мы будем использовать директивы lit.

Мы начнем с создания нового компонента на том же уровне, что и card.ts:

...

import { LitElement } from 'lit';
import { customElement } from 'lit/decorators.js';

@customElement('cards-images')
export class Cards extends LitElement {}

Вход в полноэкранный режим Выйти из полноэкранного режима

После определения внешнего @property мы получим массив объектов CardConfig:

...

import { customElement, property } from 'lit/decorators.js';

@customElement('cards-images')
export class Cards extends LitElement {

    @property({ type: Array }) cards!: CardConfig[];

}

Вход в полноэкранный режим Выход из полноэкранного режима

Теперь мы можем отобразить контейнер карточек и использовать директиву repeat для создания различных экземпляров карточки на основе конфигурации, которую мы передали в @property:

...

import { html, LitElement } from 'lit';
import { repeat } from 'lit/directives/repeat.js';

@customElement('cards-images')
export class Cards extends LitElement {

    ...

    render() {
    return html` <div class="cards">
      <ul>
        ${repeat(this.cards, (current) => html` <card-image .card=${current}></card-image> `)}
      </ul>
    </div>`;
  }

}

Войти в полноэкранный режим Выйти из полноэкранного режима

Для завершения работы нам осталось добавить стили компонента и общие стили:

...

import { css, html, LitElement } from 'lit';
import { sharedStyles } from './shared/style';

const componentStyle = css`
  .cards > ul {
    list-style: none;
    margin: 0;
    padding: 0;
  }

  @supports (display: grid) {
    .cards > ul {
      display: grid;
      grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
      grid-column-gap: 1.5rem;
      grid-row-gap: 1.5rem;
    }
  }
`;


@customElement('cards-images')
export class Cards extends LitElement {

  static styles = [sharedStyles, componentStyle];

    ...

}

Войти в полноэкранный режим Выйти из полноэкранного режима

И теперь у вас должен быть компонент, который будет отображаться вот так:

В следующей части мы рассмотрим распространение lib через пакет node с помощью реестра npm и то, как использовать компоненты в различных фреймворках/окружениях.

Оцените статью
devanswers.ru
Добавить комментарий