SvelteKit UVU試験:高速部品単体テスト


☑️ UVUは何ですか?


SvelteKit UVUテストのこのポストでは、我々はUVUでユニットテストに焦点を当てる-ルークエドワーズによる高速かつ柔軟なテストランナー.JESTと同様の機能を実行しますが、軽量化が図られます.これは、ユニットテストを実行し、sveltekitだけでなく、svelteで動作するために便利です.単体テストでは、単一のコンポーネントを分離し、制御された入力を与えられた期待される動作を生成することを確認します.あなたはSVETEコンポーネントだけでなく、ユーティリティ機能のUVUでユニットテストを実行することができます.両方見る.我々の焦点はここで単体テストになります、そして、我々は助けるためにテストライブラリを使用します.私たちはtypescriptで働きます、しかし、あなたがtypescriptに新しいならば、あなたがそれをあなたに置いておかないでください、あなたは非常に少しのtypescriptを理解する必要があります.

🔥 VUVはUVUより速いですか?


Vestestは別の新しいテストランナーです.私は見たset of tests which suggest uvu runs faster than Vitest . 両方のツールは開発中であるので、速度があなたのプロジェクトのために重要であるならば、それはあなた自身のコードベースで最新版を使っているベンチマークを走らせる価値があります.

😕 どのようにユニットテストは、プレイヤライトエンドツーエンドテストに異なりますか?


統合とエンドツーエンドテストは、他のタイプのテストです.統合テストは、複数のコンポーネントや関数(生産で使用される方法で)を組み合わせて、彼らは期待どおりに振る舞うチェックして、少し少ない粒状(単位テストより)です.エンドツーエンドのテストは、エンドユーザーと対話する最終的な結果に焦点を当てています.SvelteKitはいくつかの脚本家のサポートが付属し、おそらくエンドツーエンドのテストのためのより良いツールです.それは、脚本家があなたのアプリが異なるブラウザーでふるまう方法をシミュレーションすることができるので、それです.

🧱 我々の建物


我々はむしろ基本的なsvelteアプリにユニットテストのカップルを追加します.それは、我々が探検したとき、我々が見たのと同じものですlocal constants in Svelte with the @const tag . アプリケーションは、基本的なカラーパレットよりも多くの表示されません.簡単に言えば、それは暗い色と副詩の暗いテキストの色の名前が表示されます.ここでの目的は、パレット、または背景色とテキストラベルのコントラストを最大化することです.これはUVUでテストするものです.また、いくつかのユーティリティ機能を持って、我々はそれらの1つをテストします.あなたは、そのアプリと一緒に従うことができますが、簡単に簡単にあなたの既存のSveletKitアプリの機能ブランチを作成することができますし、そこから実行する設定を追加します.もちろん、あなた自身のユニットテストを設計します.いずれにせよ、つまずきましょう.

設定


まず使いたいパッケージを全てインストールしましょう.
pnpm add jsdom module-alias tsm uvu vite-register @testing-library/dom @testing-library/svelte @testing-library/user-event
よく知っているかもしれないKent C Dodds’ Testing Library , 特に場合は、反応の背景から来る.私はそれがここに含まれているので、svelteバージョンが表示されることができますので、反応のバージョンにはあまり異なりません.我々はそれを例に含みますが、あなた自身のプロジェクトがそれを必要としないならば、自由にそれを落とすことは自由です.
私たちは今、設定ファイルを実行し、最終的に一握りのテストを設定します.次停止:package.json .

📦 パッケージ。JSON


あなたは私たちがmodule-alias パッケージ.これは我々のテストとテストしているファイルがエイリアス参照を使用できるようにここで便利です$lib ). それが動作するように、我々はタッチをより多くの設定を追加する必要がありますpackage.json1922 下記).追加しました$tests 別名として;プロジェクトで定義した他のエイリアスを追加することも忘れないでください.
{
  "name": "svelte-each",
  "version": "0.0.1",
  "scripts": {
    "dev": "svelte-kit dev --port 3030",
    "build": "svelte-kit build",
    "package": "svelte-kit package",
    "preview": "svelte-kit preview --port 3000",
    "prepare": "svelte-kit sync",
    "test": "playwright test",
    "test:unit": "uvu tests/lib -r tsm -r module-alias/register -r vite-register -r tests/setup/register -i setup",
    "check": "svelte-check --tsconfig ./tsconfig.json",
    "check:watch": "svelte-check --tsconfig ./tsconfig.json --watch",
    "lint": "prettier --check --plugin-search-dir=. . && eslint --ignore-path .gitignore .",
    "lint:css": "stylelint \"src/**/*.{css,svelte}\"",
    "prettier:check": "prettier --check --plugin-search-dir=. .",
    "format": "prettier --ignore-path .gitignore --write --plugin-search-dir=. ."
  },
  "_moduleAliases": {
    "$lib": "src/lib",
    "$tests": "tests"
  },
  "devDependencies": {
        /* ... TRUNCATED*/
    }
また、行の単位テストを実行するための新しいスクリプトがあります11 . すぐに、次のuvu 私たちはテストフォルダを持っていますtests to tests/lib 以来、プロジェクトの設定に応じて、ダミーの脚本のテストをすることがありますtests フォルダ.あなたがすでにより広範囲な脚本家テスト(またはいくつかを加える計画)を持っているならば、あなたはUVUユニットテストを彼らの自身のフォルダーに移したいかもしれませんtests . あなたがこれをするならば、また、スクリプトでこのディレクトリを変えてください.
我々は、設定しますtests/lib フォルダをミラーsrc/lib フォルダ.例えば、テストsrc/lib/components/Palette.sveltetests/lib/components/Palette.ts .
UVU設定で動きましょう.

⚙️ UVUの設定


我々は、ガイドとしてUVUレポからSvelteの例を使用している.それに加えて、我々はまた、basf/svelte-spectre project . プロジェクトが既に持っていない場合tests フォルダを作成するプロジェクトのルートに1つです.次に、setup テストのディレクトリと、これらの4つのファイルを追加します.
import { JSDOM } from 'jsdom';
import { SvelteComponent, tick } from 'svelte';

const { window } = new JSDOM('');

export function setup() {
  global.window = window;
  global.document = window.document;
  global.navigator = window.navigator;
  global.getComputedStyle = window.getComputedStyle;
  global.requestAnimationFrame = null;
}

export function reset() {
  window.document.title = '';
  window.document.head.innerHTML = '';
  window.document.body.innerHTML = '';
}

export function render(Tag, props = {}) {
  Tag = Tag.default || Tag;
  const container: HTMLElement = window.document.body;
  const component: SvelteComponent = new Tag({ props, target: container });
  return { container, component };
}

export function fire(elem: HTMLElement, event: string, details: any): Promise<void> {
  const evt = new window.Event(event, details);
  elem.dispatchEvent(evt);
  return tick();
}
import { preprocess } from 'svelte/compiler';
import { pathToFileURL } from 'url';

const { source, filename, svelteConfig } = process.env;

import(pathToFileURL(svelteConfig).toString())
  .then((configImport) => {
    const config = configImport.default ? configImport.default : configImport;
    preprocess(source, config.preprocess || {}, { filename }).then((r) =>
      process.stdout.write(r.code),
    );
  })
  .catch((err) => process.stderr.write(err));
import path from 'path';
import { execSync } from 'child_process';
import { compile } from 'svelte/compiler';
import { getSvelteConfig } from './svelteconfig.mjs';

// import 'dotenv/config';

const processSync =
  (options = {}) =>
  (source, filename) => {
    const { debug, preprocess, rootMode } = options;
    let processed = source;
    if (preprocess) {
      const svelteConfig = getSvelteConfig(rootMode, filename);
      const preprocessor = require.resolve('./preprocess.js');
      processed = execSync(
        // `node -r dotenv/config --unhandled-rejections=strict --abort-on-uncaught-exception "${preprocessor}"`,
        `node -r module-alias/register --unhandled-rejections=strict --abort-on-uncaught-exception "${preprocessor}"`,
        { env: { PATH: process.env.PATH, source, filename, svelteConfig } },
      ).toString();
      if (debug) console.log(processed);
      return processed;
    } else {
      return source;
    }
  };

async function transform(hook, source, filename) {
  const { name } = path.parse(filename);
  const preprocessed = processSync({ preprocess: true })(source, filename);

  const { js, warnings } = compile(preprocessed, {
    name: name[0].toUpperCase() + name.substring(1),
    format: 'cjs',
    filename,
  });

  warnings.forEach((warning) => {
    console.warn(`\nSvelte Warning in ${warning.filename}:`);
    console.warn(warning.message);
    console.warn(warning.frame);
  });

  return hook(js.code, filename);
}

async function main() {
  const loadJS = require.extensions['.js'];

  // Runtime DOM hook for require("*.svelte") files
  // Note: for SSR/Node.js hook, use `svelte/register`
  require.extensions['.svelte'] = function (mod, filename) {
    const orig = mod._compile.bind(mod);
    mod._compile = async (code) => transform(orig, code, filename);
    loadJS(mod, filename);
  };
}

main();
import { existsSync } from 'node:fs';
import { dirname, resolve, join } from 'node:path';

const configFilename = 'svelte.config.js';

export function getSvelteConfig(rootMode, filename) {
  const configDir = rootMode === 'upward' ? getConfigDir(dirname(filename)) : process.cwd();

  const configFile = resolve(configDir, configFilename);

  if (!existsSync(configFile)) {
    throw Error(`Could not find ${configFilename}`);
  }

  return configFile;
}

const getConfigDir = (searchDir) => {
  if (existsSync(join(searchDir, configFilename))) {
    return searchDir;
  }

  const parentDir = resolve(searchDir, '..');

  return parentDir !== searchDir ? getConfigDir(parentDir) : searchDir; // Stop walking at filesystem root
};
必要なら.env プロジェクトの環境変数のサポートdotenv パッケージ.その後、行をコメント解除する6 インregister.ts 置換線18 並んで17 .

✅ テスト、テスト、1、2、3 .


それが必要な設定です.最初のテストを加えましょう.これはユーティリティ関数をテストします.機能のアイデアは、テキストの色を選択するのに役立つ(どちらか白または黒)は、ほとんどの入力の背景色に対照的です.
import type { RGBColour } from '$lib/types/colour';
import { textColourClass } from '$lib/utilities/colour';
import { reset, setup } from '$tests/setup/env';
import { test } from 'uvu';
import assert from 'uvu/assert';

test.before(setup);
test.before.each(reset);

test('it returns expected colour class', () => {
  const blackBackground: RGBColour = { red: 0, green: 0, blue: 0 };
  assert.equal(textColourClass(blackBackground), 'text-light');

  const whiteBackground: RGBColour = { red: 255, green: 255, blue: 255 };
  assert.equal(textColourClass(whiteBackground), 'text-dark');
});

test.run();
ここで最も重要なのはtest.run() 最後に……何度かやった😅. 行にエイリアスを使用できる方法に注意してください13 . あなたはfull range of assert methods available in the uvu docs .

💯 スベート成分試験


スナップショットとテストライブラリを使用して、Svelteのコンポーネントテストを行います.UVUをつくったルークエドワーズreflects his philosophy on snapshots in the project . これは、なぜUVUのスナップショットは、少し別のあなたがジェストで精通している可能性があります動作する理由について説明します.
import Palette from '$lib/components/Palette.svelte';
import { render, reset, setup } from '$tests/setup/env';
import { render as customRender } from '@testing-library/svelte';
import { test } from 'uvu';
import assert from 'uvu/assert';

const colours = [
  { red: 0, green: 5, blue: 1 },
  { red: 247, green: 244, blue: 243 },
  { red: 255, green: 159, blue: 28 },
  { red: 48, green: 131, blue: 220 },
  { red: 186, green: 27, blue: 29 },
];

const colourSystem = 'hex';
const names = ['Deep Fir', 'Hint of Red', 'Tree Poppy', 'Curious Blue', 'Thunderbird'];

test.before(setup);
test.before.each(reset);

test('it renders', () => {
  const { container } = render(Palette, { colours, colourSystem, names });

  assert.snapshot(
    container.innerHTML,
    '<section class="colours svelte-45k0bw"><article aria-posinset="1" aria-setsize="5" class="colour text-light svelte-45k0bw" style="background-color: rgb(0, 5, 1);">Deep Fir <span class="colour-code svelte-45k0bw">#000501</span> </article><article aria-posinset="2" aria-setsize="5" class="colour text-dark svelte-45k0bw" style="background-color: rgb(247, 244, 243);">Hint of Red <span class="colour-code svelte-45k0bw">#f7f4f3</span> </article><article aria-posinset="3" aria-setsize="5" class="colour text-dark svelte-45k0bw" style="background-color: rgb(255, 159, 28);">Tree Poppy <span class="colour-code svelte-45k0bw">#ff9f1c</span> </article><article aria-posinset="4" aria-setsize="5" class="colour text-dark svelte-45k0bw" style="background-color: rgb(48, 131, 220);">Curious Blue <span class="colour-code svelte-45k0bw">#3083dc</span> </article><article aria-posinset="5" aria-setsize="5" class="colour text-light svelte-45k0bw" style="background-color: rgb(186, 27, 29);">Thunderbird <span class="colour-code svelte-45k0bw">#ba1b1d</span> </article></section>',
  );
});

test('text colour is altered to maximise contrast', () => {
  const { getByText } = customRender(Palette, { colours, colourSystem, names });
  const $lightText = getByText('Deep Fir');
  assert.is($lightText.className.includes('text-light'), true);

  const $darkText = getByText('Hint of Red');
  assert.is($darkText.className.includes('text-dark'), true);
});

test.run();
行に注意22 & 31 どのようにコンポーネントとその小道具をインポートします.インライン2427 スナップショットを作成する方法を参照してください.その間に3 and 3133 UVUでテストライブラリを使う方法を見ます.
テストをチェックするには、次のコマンドを実行します.
pnpm run test:unit
端末から.

🙌🏽 SvelteKit UVUテスト:ラップアップ


この投稿では、
  • UVUとは、SveletKitを使用してコンポーネントのテストやユーティリティ機能をテストする方法です.
  • UVUとSvelteを使ったテストライブラリの使い方
  • どのようにスナップショットUVUで動作します.
  • 私はあなたの仕事またはサイドプロジェクトで使用することができますこの記事で少なくとも1つのことがあることを願っています.また、あなたが設定のより多くの説明を感じるならば、私に知らせてください.
    あなたはexample project with all of this setup and config on the Rodney Lab Git Hub repo . 以下のコメントをドロップするか、またはチャットに達するElement 同様に改善や質問のための提案がある場合.

    🙏🏽 フィードバック


    この動画を見るには、ログインしてください.閉じるこの動画はお気に入りから削除されています.私がそれを改善することができるどんな方法があるかどうか知らせてください.あなた自身のプロジェクトでコードまたはスターターを使用することを望みます.ツイッターであなたの仕事を共有してください、そして、私があなたが何をしたかについて見ることができるように、私に言及を与えてください.最後に私にあなたが見たいと思っている他の短いビデオのアイデアを教えてください.記事を読む上で、さらに以下のタッチを取得する方法を見つける.もしこの投稿が役に立ちましたら、ほんのわずかな貢献さえすることができますがconsider supporting me through Buy me a Coffee .
    最後に、あなたのソーシャルメディアアカウントの投稿を共有すること自由に感じているすべてのあなたの信者は、それが役に立つでしょう.だけでなく、以下のコメントを残して、あなたはTwitterやaskRodney on Telegram . また、further ways to get in touch with Rodney Lab . 定期的に投稿SvelteKit だけでなくSearch Engine Optimisation 他の話題の間で.Also subscribe to the newsletter to keep up-to-date 我々の最新プロジェクトで.