#moduleNameMapper
Explore tagged Tumblr posts
Text
Exploring the Power of moduleNameMapper in Jest for Seamless Testing
If you're a developer who's passionate about writing efficient and reliable code, then you're probably familiar with the importance of testing. Testing ensures that your code functions as intended and helps you catch bugs before they cause havoc in production. One tool that has gained significant popularity in the JavaScript community for testing is Jest. In this article, we'll dive deep into a powerful feature of Jest called moduleNameMapper and how it can enhance your testing experience.
Table of Contents
- Introduction to Jest and Testing - Why testing is crucial for software development - Overview of Jest and its features - Understanding moduleNameMapper - What is moduleNameMapper? - How does moduleNameMapper work? - Use cases and benefits of using moduleNameMapper - Implementing moduleNameMapper in Your Project - Step-by-step guide to setting up moduleNameMapper - Practical examples of using moduleNameMapper - Best Practices for Effective Testing with moduleNameMapper - Keeping your test suite organized - Writing meaningful test descriptions - Leveraging moduleNameMapper for mocking - Advanced Techniques and Tips - Combining moduleNameMapper with other Jest features - Overcoming common challenges - Performance considerations and optimizations - Conclusion
Introduction to Jest and Testing
Why testing is crucial for software development In the world of software development, testing plays a pivotal role in ensuring the quality and reliability of your code. It allows you to identify and fix issues early in the development process, reducing the likelihood of encountering bugs in production. Overview of Jest and its Features Jest, developed by Facebook, is a widely used JavaScript testing framework. It's known for its simplicity and robustness, making it a favorite among developers for writing tests for their applications.
Understanding moduleNameMapper
What is moduleNameMapper? moduleNameMapper is a configuration option in Jest that enables you to map module names to different paths or mock implementations. This feature is particularly useful when dealing with complex project structures or third-party libraries. How does moduleNameMapper work? When Jest encounters an import statement, it checks the moduleNameMapper configuration to determine if a mapping exists for the imported module. If a mapping is found, Jest uses the specified path or mock implementation instead of the actual module. Use cases and benefits of using moduleNameMapper - Simplifying testing of components with external dependencies. - Mocking modules that perform network requests or have side effects. - Enhancing test performance by substituting heavy modules with lightweight alternatives.
Implementing moduleNameMapper in Your Project
Step-by-step guide to setting up moduleNameMapper - Open your Jest configuration file. - Locate the moduleNameMapper option and define your mappings. - Run your tests, and Jest will apply the mappings during test execution. Practical examples of using moduleNameMapper Example 1: Mocking API calls javascriptCopy code "moduleNameMapper": { "^api/(.*)": "/__mocks__/api/$1.js" } Example 2: Mapping CSS modules javascriptCopy code "moduleNameMapper": { ".(css|scss)$": "identity-obj-proxy" }
Best Practices for Effective Testing with moduleNameMapper
Keeping your test suite organized Organize your tests into descriptive folders and files to maintain a clear structure. This ensures that tests are easy to locate and manage, especially as your project grows. Writing meaningful test descriptions Use descriptive test names that clearly convey the purpose of each test. This makes it easier for developers to understand the test's intent and quickly identify issues. Leveraging moduleNameMapper for mocking Take advantage of moduleNameMapper to mock external dependencies or complex modules. This helps isolate the unit of code being tested and ensures reliable test results.
Advanced Techniques and Tips
Combining moduleNameMapper with other Jest features Pair moduleNameMapper with snapshot testing or mocking frameworks like jest.mock to create comprehensive and accurate tests. Overcoming common challenges Address challenges such as circular dependencies or dynamically generated paths by configuring appropriate mappings in moduleNameMapper. Performance considerations and optimizations While moduleNameMapper can improve test performance, be mindful of potential bottlenecks. Evaluate the impact of your mappings on overall test execution time.
Conclusion
Incorporating moduleNameMapper into your Jest testing strategy can significantly enhance your ability to write thorough and effective tests. By intelligently mapping module names, you can seamlessly mock dependencies, simplify complex scenarios, and ultimately build more reliable software.
FAQs
- What is the purpose of moduleNameMapper in Jest? moduleNameMapper allows you to map module names to different paths or mock implementations, enhancing testing flexibility. - Can moduleNameMapper be used alongside other Jest features? Absolutely! moduleNameMapper can be combined with various Jest features like mocking and snapshot testing for comprehensive tests. - Does moduleNameMapper impact test performance? While moduleNameMapper can improve performance, improper usage or excessive mappings may lead to performance issues. - Can I use regular expressions in moduleNameMapper configurations? Yes, you can use regular expressions to define mappings in the moduleNameMapper configuration. - Is moduleNameMapper exclusive to JavaScript projects? No, moduleNameMapper can be used in any project where Jest is employed for testing, regardless of the programming language used. Read the full article
0 notes
Text
ブックマークレットをテスト駆動開発する
前回、TypeScriptとGulpで無駄にモダンなブックマークレット開発環境を作ってみました。せっかくそこまで環境を作ったので、今回はテスト駆動開発できるようにしてみました。
��前回の記事はこちら) GulpとTypeScriptでブックマークレット開発環境を作ってみた - Trial and Spiral
テスト環境構築
テストフレームワークとして、Jestを使います。また、ブックマークレットである以上
動かすためのページに行く
ブックマークレットのJavaScript(即時関数)を実行
という手順が必要になります。通常のユニットテストだけでは不十分なので今回はPuppeteerというヘッドレスブラウザも合わせて使います。要はコードからブラウザ操作を自動でやらせると思っていただければ。
関連ライブラリのインストール
ちょうど良く、jest-puppeteerというライブラリがあるのでそれを入れます。 jest-puppeteer puppeteer jest
READMEにあるように関連ライブラリも一緒に入れます。
$ yarn add -D jest-puppeteer puppeteer jest
さらにTSとGulpでやっているので必要なものを入れます。
$ yarn add -D gulp-jest ts-jest
そして関係する型も入れます
$ @types/expect-puppeteer @types/jest @types/jest-environment-puppeteer @types/puppeteer
設定ファイル
jestの設定はpackage.jsonに書いてもいいんですが、見通しを良くするため、今回はファイルを別に分けてみます。ファイルはルートディレクトリにjest.config.jsを作って以下を書きます。
また、jsonではなくjsファイルなのでコメントアウトやJS式が使える利点もありますね。
jest.config.js
module.exports = { preset: `jest-puppeteer`, moduleNameMapper: { '^#/(.+)': `<rootDir>/dist/$1`, }, moduleFileExtensions: [`ts`, `tsx`, `js`], transform: { '^.+\\.(ts|tsx)$': `ts-jest`, }, globals: { 'ts-jest': { tsConfig: `tsconfig.json`, }, }, testMatch: [`**/__tests__/*.+(ts|tsx|js)`], }
一番重要なのは最初のpreset: 'jest-puppeteer'とglobalsの指定ですね。それ以外はお好みです。
あとはオプショナルとして、puppeteerの設定も可能です。設定なしのデフォルトでも問題なく動いてくれますのでなくても大丈夫ですが、言及しておくと同じくルートディレクトリにjest-puppeteer.config.jsを作って設定できます、たとえば
jest-puppeteer.config.js
module.exports = { launch: { dumpio: true, headless: true, }, browserContext: `default`, }
みたいな感じです。特筆すべきはheadless: falseにするとヘッドレスモードをオフにできるので実際にGoogleChromeが動く様子がみれます。デバッグで使うこともありますね。
テストを書いてみる
設定ファイルに指定したようにテスト用のファイルは__tests__というディレクトリの中に作っていきます。前回にサンプルとして「見てるページのタイトルをプロンプトに表示する」というブックマークレットを作りました。まずはそのテストを書いてみます。
__tests__の中にsample.test.tsというファイルを作って以下のようにテストを書いてみます。
sample.test.ts
describe(`Google`, () => { beforeAll(async () => { await page.goto(`https://google.com`) }) it(`should be titled "Google"`, async () => { await expect(page.title()).resolves.toMatch(`Google`) }) it(`should be title in prompt`, async () => { let value await page.on(`dialog`, async dialog => { value = await dialog.defaultValue() await dialog.accept() }) await page.addScriptTag({ path: './dist/sample.js' }) expect(value).toMatch(`Google`) }) })
少し解説すると、beforeAllでサンプルとしてGoogleのトップに飛ぶようにしています。
最初のテストはブックマークレット関係なしでGoogleのサイトに飛べてるか、タイトルの値が取得できるかを見ています。このテストがパスしないのであれば、ブックマークレット以外の部分で問題があると考えたほうが良いですね。
2つめのテストが今回のテストです。ポイントはいくつかあります。
まず先にダイアログ(プロンプト)の表示を取得するように設定しておきます。具体的にはpage.on('dialog',でダイアログを待って、dialog.defaultValue()はダイアログが開いたときの入力欄の文字列を取得できます。取得したらその一応念のためにaccept()でダイアログを閉じておきます(OKを押したときの動作)。
その後でpage.addScriptTag({ path: './dist/sample.js' })でブックマークレットを動作させます。ちょっと強引ですがこの方法に落ちつきました。もしもっと良い方法があれば教わりたいです。 なお注意点としてはこのパスはテストを走らせるコマンドを叩くところからの相対パス(=ルートディレクトリから)で書く必要があります。
pathで指定したjsファイルをページに対してスクリプトとして挿入します。このJSはブックマークレット、すなわち即時関数であるためaddしたらすぐに実行される流れです。
そうしてあらかじめ待ち受けていたダイアログの文字列取得が動いて、valueに入るので、それをexpectでアサーションにかける、という流れですね。
さあ、ここまでできたら
$ jest
とテストを走らせてみましょう。2つのテストがパスすればOKです。
テストをGulpで扱う
せっかくビルド作業をGulpで扱っているのだからテストもGulpで扱うようにしてみます。というのもテストする対象がJSのなのでテスト前に都度都度ビルドする必要がある事情もありますので。
先にファイルから載せてしまうと
gulpfile.ts
import gulp from 'gulp' import eslint from 'gulp-eslint' import ts from 'gulp-typescript' import uglify from 'gulp-uglify' import replace from 'gulp-replace' import jest from 'gulp-jest' const tsProject = ts.createProject(`tsconfig.json`) const srcDir = `src` const destDir = `dist` const testDir = `__tests__` export const build = done => { gulp .src(`${srcDir}/*.ts`) .pipe(eslint({ useEslintrc: true })) .pipe(eslint.format()) .pipe(eslint.failAfterError()) .pipe(tsProject()) .pipe( uglify({ mangle: true, compress: true, }) ) .pipe(replace(/^(.*)$/, `javascript:$1`)) .pipe(gulp.dest(destDir)) done() } export const test = done => { gulp.src(`${testDir}/*.ts`).pipe(jest({})) done() } export const dev = done => { gulp.series(`build`, `test`)(done()) } export default build
とこうなりました。前回から追加したものを順に説明します。
まずGulp内でJestを実行できるように読み込みます。
import jest from 'gulp-jest'
テスト用のディレクトリを定義しておきます。
const testDir = `__tests__`
testというタスクにjestのテストを割り合てます。
export const test = done => { gulp.src(`${testDir}/*.ts`).pipe(jest({})) done() }
ビルドして続けてテストする一連を1つのタスクにします。
export const dev = done => { gulp.series(`build`, `test`)(done()) }
ちょいちょいdone()と出てきてますが、コールバックで終わりを明示しないとgulp.seriesで上手く扱えないようです。このへんJSらしくasync functionで扱えると良いんですが、v3からのやりかたもあり、最適解が良くわかりません。むむむ。
あとは、一応yarnやNPM経由でも実行しすいようにしておきましょうか。 package.jsonに
package.json
{ "scripts": { "build": "gulp build", "test": "gulp test", "dev": "gulp dev" }, }
を追記しておきましょう。
感想
やはり前回も言いましたが、たかだかブックマークレットでここまでやるのはオーバーキル気味ですね。個人的にはPuppeteer初めて触ってりしていろいろ楽しめた反面、ブックマークレットの動かし方がちょっとスマートじゃないのでモニョモニョしています。
またテスト環境的には本当は実際のページではなく用意したフィクスチャでやりたいところです。ネット環境が必須になってローカルだけで完結できないですし、テストに使ってる先に変更があったらテストが落ちてしまうので。
さらに、ブックマークレット内でCDNのjQueryを使う方法があって、そうするとちょっと楽にブックマークレット書けるんですが、その場合読み込み待ちをテスト内で実現できず上手くテストを書くことができませんでした。それでネイティブJSで実装しなおしたんですが、jQueryの読み込み待ちがなくなったことで高速化したので結果的にや良かったです。
まあ強引なテスト方法であることは否めないですが、やっぱりエンジニアたるものポチポチテストするよりはテストコードで動作を担保したいので、なかなか良いエクササイズでした。
最後にこの作成を環境をGitHubに上げたので気が向いたら��考にしてみてください。
AquiTCD/ts-bookmarklet-workbench: a workbench to build bookmarklets by typescript with jest
from Trial and Spiral https://blog.solunita.net/test-driven-develop-bookmarklet/
0 notes