See how Stencil fits into the entire Ionic Ecosystem ->
Stencil is part of the Ionic Ecosystem ->

エンドツーエンドのテスト

E2Eテストは、実際のブラウザーでコンポーネントを検証します。たとえば、 my-componentにX属性がある場合、子コンポーネントはテキストYをレンダリングし、イベントZを受信することを期待します。レンダリングテストにPuppeteerを使用することにより(ブラウザの動作をシミュレートするノード環境ではなく)、より良い結果を得るために、エンドツーエンドのテストを実際のブラウザ内で実行できます。

ステンシルは、JestおよびPuppeteerのテストに役立つ多くのユーティリティ関数を提供します。たとえば、コンポーネントのシャドウdomは、Puppeteer上に構築されたStencilユーティリティ関数を使用してクエリおよびテストできます。テストは、模擬HTMLコンテンツを提供できるだけでなく、Puppeteerが開いてStencilの開発サーバーでテストできるアプリのURLにアクセスすることもできます。

エンドツーエンドのテストでは、テストを実際に実行する前に、新しいビルド、dev-server、およびpuppeteerブラウザーインスタンスを作成する必要があります。追加されたビルドの複雑さにより、 stenciltestコマンドはビルド要件を事前に整理することができます。

E2Eテストを実行するには、 stencil test--e2eを実行します。デフォルトでは、 .e2e.tsで終わるファイルが実行されます。

ステンシルのE2Eテストは、次のAPIで提供され、 @stencil/core/testingから入手できます。 ほとんどのメソッドは非同期であり、Promisesを返します。 asyncawaitを使用して、テストを整理します。

  • newE2EPage:新しい E2EPageオブジェクトをインスタンス化するには、各テストの開始時に呼び出す必要があります

  • E2EPageは、テストの作成を簡素化するためのPuppeteerのラッパーユーティリティです。 E2EPageのいくつかの便利なメソッドは次のとおりです。

  • setContent(html: string):ページのコンテンツを設定します。 これは、テスト対象のコンポーネントのマークアップを含める場所です。

  • find(selector: string):セレクターに一致する要素を検索します。 document.querySelectorに似ています。

  • waitForChanges():StencilとPuppeteerの両方に非同期アーキテクチャがあり、これはパフォーマンスにとって良いことです。 すべての呼び出しは非同期であるため、コンポーネントに変更が加えられたときに await page.waitForChanges()が呼び出される必要があります。

E2Eテストの例には、次の定型文があります。

import { newE2EPage } from '@stencil/core/testing';

describe('example', () => {
  it('should render a foo-component', async () => {
    const page = await newE2EPage();
    await page.setContent(`<foo-component></foo-component>`);
    const el = await page.find('foo-component');
    expect(el).not.toBeNull();
  });
});

E2Eテストの例

import { newE2EPage } from '@stencil/core/testing';

it('should create toggle, unchecked by default', async () => {
  const page = await newE2EPage();

  await page.setContent(`
    <ion-toggle class="pretty-toggle"></ion-toggle>
  `);

  const ionChange = await page.spyOnEvent('ionChange');

  const toggle = await page.find('ion-toggle');

  expect(toggle).toHaveClasses(['pretty-toggle', 'hydrated']);

  expect(toggle).not.toHaveClass('toggle-checked');

  toggle.setProperty('checked', true);

  await page.waitForChanges();

  expect(toggle).toHaveClass('toggle-checked');

  expect(ionChange).toHaveReceivedEventDetail({
    checked: true,
    value: 'on'
  });
});

E2Eテストレシピ

ShadowDOMで要素を検索する

「ピアス」セレクター >>>を使用して、コンポーネントのシャドウルート内のオブジェクトをクエリします。

const el = await page.find('foo-component >>> .close-button');

コンポーネントに@Prop()を設定します

page。$ eval(Puppeteer APIの一部)を使用して、Propを設定するか、コンポーネントを操作します。

// create a new puppeteer page
// load the page with html content
await page.setContent(`
      <prop-cmp></prop-cmp>
    `);

// select the "prop-cmp" element
// and run the callback in the browser's context
await page.$eval('prop-cmp', (elm: any) => {
  // within the browser's context
  // let's set new property values on the component
  elm.first = 'Marty';
  elm.lastName = 'McFly';
});

// we just made a change and now the async queue need to process it
// make sure the queue does its work before we continue
await page.waitForChanges();

外部参照を使用してコンポーネントに@Prop()を設定します

page。$ evalには分離されたスコープがあるため、外部参照を明示的に渡す必要があります。そうしないと、undefinedエラーが発生します。 これは、別のファイルからデータをインポートしたり、同じファイル内の複数のテストでモックデータを再利用したりする場合に役立ちます。

const props = {
  first: 'Marty',
  lastName: 'McFly',
};

await page.setContent(`<prop-cmp></prop-cmp>`);

await page.$eval('prop-cmp',
  (elm: any, { first, lastName }) => {
    elm.first = first;
    elm.lastName = lastName;
  },
  props
);

await page.waitForChanges();

コンポーネントで@Method()を呼び出す

const elm = await page.find('method-cmp');
elm.setProperty('someProp', 88);
const methodRtnValue = await elm.callMethod('someMethod');

入力フィールドに入力します

const page = await newE2EPage({
  html: `
      <dom-interaction></dom-interaction>
    `
});

const input = await page.find('dom-interaction >>> .input');

let value = await input.getProperty('value');
expect(value).toBe('');

await input.press('8');
await input.press('8');
await input.press(' ');

await page.keyboard.down('Shift');
await input.press('KeyM');
await input.press('KeyP');
await input.press('KeyH');
await page.keyboard.up('Shift');

レンダリングされたコンポーネントのテキストを確認する

await page.setContent(`
      <prop-cmp first="Marty" last-name="McFly"></prop-cmp>
    `);

const elm = await page.find('prop-cmp >>> div');
expect(elm).toEqualText('Hello, my name is Marty McFly');

コンポーネントのHTMLを確認する

shadowRootコンテンツの場合:

        expect(el.shadowRoot).toEqualHtml(`<div>
        <div class=\"nav-desktop\">
          <slot></slot>
        </div>
      </div>`);
    });

For non-shadow content:

        expect(el).toEqualHtml(`<div>
        <div class=\"nav-desktop\">
          <slot></slot>
        </div>
      </div>`);
    });

CD/CIでのe2eテストの自動化に関する警告

かなり一般的な方法であるため、継続的デプロイ/統合(CD/CI)システムでエンドツーエンドのテストを自動的に実行することをお勧めします。 ただし、環境によっては、構成を微調整する必要がある場合があります。 その場合、 stencil.config.tsファイルのconfigオブジェクトには、パイプラインでヘッドレスChromeが実際にどのように使用されるかを変更するパラメーターを受け入れる testing属性があります。

Gitlab CI環境で必要になる可能性のある構成の例:

export const config: Config = {
  namespace: 'Foo',
  testing: {
    /**
     * Gitlab CI doesn't allow sandbox, therefor this parameters must be passed to your Headless Chrome
     * before it can run your tests
     */
    browserArgs: ['--no-sandbox', '--disable-setuid-sandbox'],
  },
  outputTargets: [
    { type: 'dist' },
    {
      type: 'www',
    },
  ],
};

この問題の可能性について詳しくは、ドキュメントのこの部分を確認してください。

BackNext
Contributors