自動化

Cypressとは|E2E・コンポーネントテストの仕組みとcy.mountの書き方

Cypressとは|E2E・コンポーネントテストの仕組みとcy.mountの書き方

Cypressとは、ブラウザで動くWebアプリを対象にしたテスト実行基盤です。E2Eテスト・コンポーネントテスト・APIテストを1つのアプリで扱い、テストコードをアプリと同じブラウザの中で走らせる点に設計上の特徴があります。開発元のCypress.ioは、ローカルにインストールして使うオープンソースの「Cypress App」と、実行結果を記録・分析する有料サービス「Cypress Cloud」の二層で提供しています。

なかでもコンポーネントテストは、コンポーネントを実ブラウザに直接マウントして検証する仕組みです。jsdomのような模擬DOMを介さないため、CSSの効いた見た目のまま動かし、DevToolsで要素を覗きながらデバッグできます。

ただしこの機能は、日本語の解説記事が書かれた頃とは対応範囲が大きく変わりました。2025年1月16日公開のCypress 14.0.0が、create-react-app・Vue CLI(@vue/cli-service)・Vue 2・Nuxt.js 2のコンポーネントテスト対応を一括で削除しています。当時の手順をそのままなぞっても、いまのCypressでは起動しません。

この記事では、Cypressという製品の輪郭と他ツールとの違いを押さえたうえで、主力のcy.mountの書き方を実際のコードで示し、cypress.configのdevServer設定、最新版15.21.1(2026年8月25日公開)時点の公式対応フレームワーク、旧手順から移行するときにつまずく箇所を整理します。ページ遷移をまたぐテストの書き方はE2EテストをCypressで自動化する方法とその実践例で扱っています。

まとめ

  • CypressはWeb向けのテスト実行基盤。E2E・コンポーネント・APIの各テストを1つのアプリで扱う
  • テストコードがアプリと同じブラウザ内で動くため、要素の出現を待つ処理を自分で書かずに済む
  • 製品はMITライセンスのCypress App(無償)と、記録・分析を担う有料のCypress Cloudに分かれる
  • 2ブラウザの同時操作・複数タブ・1テスト複数スーパードメインは設計上の制約として残る
  • コンポーネントテストは Cypress 11.0.0(2022年11月8日)でGA。React・Next.js・Angular・Vueが対象
  • cy.mount はフレームワークごとに引数が異なるものの、「describe / it で囲む → cy.mount → cy.get → should」という流れは共通
  • v15の公式対応は React 18-19、Vue 3、Angular 18-21、Next.js 14-16、Svelte 5(Alpha)。create-react-app・Vue CLI・Vue 2・Nuxt.js 2は14.0.0で打ち切り
  • devServer.framework の公式定義は react / vue / svelte / next / angular の5つ
  • バンドラにViteを使う場合、15.0.0以降は設定ファイルをESM形式にしないと読み込めない
  • 要素の指定は data-cy などのテスト専用属性で行い、CSSクラスやDOM構造に依存させない

まず押さえたいのは、Cypressがどういう仕組みでブラウザを動かしているかです。ここが他のテストツールとの違いをそのまま説明します。

Cypressとは何か|ブラウザの中で動くテスト実行基盤という設計

WebDriverを介さない実行モデルと自動待機が効いてくる理由

一般的なブラウザ自動化ツールは、テストコードをNode.jsなどの外部プロセスで実行し、WebDriverのような通信プロトコル越しにブラウザへ命令を送ります。命令とアプリの間にネットワーク的な往復が挟まるため、要素がまだ描画されていない状態で操作命令が届くことが起こりえます。

Cypressはここが異なる設計です。テストコードはアプリと同じブラウザ、同じ実行ループの中で動き、その外側に立つNode.jsプロセスがファイル操作やネットワーク層の制御を受け持ちます。DOMやwindowオブジェクトへ直接触れる位置にテストが居るため、要素の状態を毎フレーム見に行けます。

この構造から出てくるのが、リトライアビリティと呼ばれる挙動です。cy.get は要素が見つかるまで、should はアサーションが通るまで、既定のタイムアウト(4秒)の範囲で自動的にやり直します。テストコードに sleep 相当の待機を散りばめる必要がなく、待ち時間の当て推量に起因する不安定なテストが減ります。

デバッグの見え方も同じ構造から来ています。実行中のコマンドが一覧に残り、任意の時点をクリックするとその瞬間のDOMスナップショットへ戻れます。ブラウザ内で完結しているからこそ、失敗した1手前の画面をそのまま検分できるわけです。

Cypress AppとCypress Cloudという二層の製品構成

Cypressという名前は、性格の異なる2つのものを指します。混同すると費用の話が噛み合わなくなるので、最初に切り分けておきます。

名称 位置づけ 費用 主な役割
Cypress App ローカル導入のOSS 無償(MIT) テストの記述と実行
Cypress Cloud SaaS 無料枠あり・以降は有料 実行結果の記録と分析
UI Coverage Cloudの追加機能 個別見積り テスト網羅範囲の可視化
Cypress Accessibility Cloudの追加機能 個別見積り アクセシビリティ検査

テストを書いて回すだけならCypress Appで完結し、費用は発生しません。npmから cypress パッケージを入れれば、そのままCIでも実行できます。ライセンスはMITで、npmレジストリ上の15.21.1も同じ表記です。

Cypress Cloudは、CIで走らせた結果を蓄積して並列実行の割り振りや不安定なテストの検出に使うサービスです。2026年8月時点の公式価格ページでは、無償のStarterが月500テスト結果まで、Teamが年払い799ドル(月あたり67ドル)から、Businessが年払い3,199ドル(月あたり267ドル)から、Enterpriseは個別見積りという構成でした。金額と枠は改定されるため、判断の直前に公式ページで確認してください。

対応ブラウザと対応言語、ライセンス条件から見た導入前の確認事項

テストコードはJavaScriptまたはTypeScriptで書きます。Selenium系のようにJavaやPython、C#から呼ぶ選択肢はありません。フロントエンドと同じ言語でテストを書けるのは利点である一方、テスト担当者がJavaScript系の言語に触れない体制だと導入の障壁になります。

対応ブラウザは、Chrome系ブラウザ・Firefox・WebKit(Safariのブラウザエンジン)です。Cypressにバンドルされているelectron以外は、ローカルまたはCI環境側にブラウザがインストールされている必要があります。実行時のブラウザ指定は --browser フラグで行います。

npx cypress run --browser chrome
npx cypress run --browser firefox

Node.jsの要求範囲も確認対象です。15.21.1のpackage.jsonが宣言する engines.node^20.1.0 || ^22.0.0 || >=24.0.0 で、Node.js 18と23はサポート対象から外れています。CIのランナーイメージが古いまま15系へ上げると、インストール段階で弾かれます。

2ブラウザの同時操作や複数タブなど設計上できないことの線引き

ブラウザの中で動く構造は利点だけを生みません。公式ドキュメントのTrade-offsは、恒久的な制約を明示しています。導入判断では、この制約が自分たちのテスト対象に当たるかを先に確かめるのが順序です。

  • 汎用の自動化ツールではない(クロール・スクレイピング・性能計測・他社サイト操作は対象外)
  • 2つのブラウザを同時に走らせて相互作用を検証することはできない
  • 1つのテストは1つのスーパードメインに紐づく。ドメインをまたぐ遷移は cy.origin で扱う
  • ネイティブイベントやモバイルアプリのイベントには対応しない
  • iframeの扱いは限定的(同一オリジンのiframeは参照できる)
  • cy.hover() という専用コマンドは存在せず、回避策で書く

チャット機能の送信側と受信側を別ブラウザで同時に動かす、といった検証はCypressの守備範囲外です。この種の要件が中核にあるなら、後述のとおり別ツールを選ぶほうが早く着地します。

SeleniumやPlaywrightと比較したときのCypressの立ち位置

「Cypressとは何か」を一段深く理解するには、同じE2Eテストの領域にある他ツールとの差分を見るのが早道です。3者の性格は、実行モデルの違いからほぼ導けます。

観点 Cypress Selenium Playwright
実行位置 アプリと同じブラウザ内 WebDriver経由の外部制御 Node側からCDP等で制御
記述言語 JavaScript / TypeScript Java・Python・C#ほか JS/TS・Python・Java・.NET
待機の扱い 既定で自動リトライ 明示的な待機を自分で書く 既定で自動待機
複数タブ 非対応 対応 対応
対応ブラウザ Chrome系・Firefox・WebKit 主要ブラウザ全般 Chromium・Firefox・WebKit
デバッグ 時系列スナップショット ログとスクリーンショット Trace Viewer

Seleniumは適用範囲の広さで選ばれます。WebDriverはW3C勧告として標準化されており、言語もブラウザも縛られません。既存のテスト資産がJavaやC#で積み上がっているなら、そちらに寄せるほうが合理的です。書き方の現状はSeleniumの使い方|Selenium 4でWebDriverの手動設定が不要になった書き方で整理しています。

Playwrightは、複数タブ・複数コンテキスト・ドメインをまたぐ操作を素直に書ける点でCypressの制約を埋めます。設計思想の違いはPlaywrightとは|仕組み・できること・Seleniumとの違いを解説にまとめました。実ブラウザでコンポーネント単位の検証を行う機能も持っており、そちらはPlaywright Component Testとは何か?概要と基本的な特徴を徹底解説で扱っています。

ではCypressが選ばれる理由はどこにあるか。実装者が自分でテストを書き、失敗したときに自分で直す体制で効いてきます。ブラウザ内で完結する構造ゆえに、コマンドログから任意の時点へ戻って原因を追える。この開発者体験が、テストを書く人と直す人が同じチームにいる現場で回転数を上げます。

コンポーネントテストとE2Eテストの役割分担をどこで線引きするか

コンポーネントテストが担う検証範囲と待ち処理を書かずに済む理由

コンポーネントテストは、アプリ全体を起動せずに単一のコンポーネントだけをブラウザにマウントし、入力(props)に対する表示と、操作に対するイベント発火を確かめます。バックエンドもルーティングも不要なので、UIの分岐やエッジケースを網羅する用途に向きます。

Cypressの場合、レンダリングが終わるまで待つ処理を書かずに済む点が実務では効きます。公式ドキュメントも、アサーションはコンポーネントの描画・更新が済んでから実行されるため waitForact()、手書きのタイムアウトは不要だと明記しています。

E2Eテストとの分担とテストピラミッド上での位置づけの考え方

E2Eテストは、実際のURLを開いてページ遷移・ログイン・API通信まで含めた一連の流れを検証します。守備範囲が広いぶん実行時間が長く、失敗したときの原因切り分けにも時間がかかります。Mike Cohnが2009年の著書『Succeeding with Agile』で示したテストピラミッドが、UIを通したテストを頂点=最少に置いているのは、この費用差が理由です。

分担の目安ははっきりしています。入力値ごとの表示差分・エラー表示・ボタンの活性制御はコンポーネントテスト、画面をまたぐ業務フローとサーバ連携はE2Eテストです。公式ドキュメントもNext.jsについて、getServerSidePropsgetStaticProps はサーバ側でしか動かずコンポーネントテストでは実行されないため、ページ単位の検証はE2Eテストを推奨し、コンポーネントテストは個々のコンポーネントに使うよう明記しています。

どこまでをE2Eテストで見るかという配分そのものに迷うなら、ツール選定より前にE2E(エンドツーエンド)テストのベストプラクティス|結合テストとの違いとツール選定で層の切り方を決めてから戻ってくると、この記事の判断が早くなります。

同じ「実ブラウザでコンポーネントを動かす」方式は他ツールにもあります。選定段階ならPlaywright Component Testとは何か?概要と基本的な特徴を徹底解説Vitest Browser Modeの導入・セットアップ方法を徹底解説と併せて比較してください。

cy.mountでコンポーネントをマウントするテストコードの書き方

フレームワーク別に見るcy.mountの引数と共通する記述の骨格

テストファイルの骨格はどのフレームワークでも同じです。describe でファイル単位のまとまりを作り、it に1件のテストを書き、その中で cy.mount を呼びます。React の場合はJSXをそのまま渡します。

import React from 'react'
import Stepper from './Stepper'

describe('<Stepper />', () => {
  it('mounts', () => {
    cy.mount(<Stepper />)
  })
})

Vue・Svelte はコンポーネントオブジェクトを、Angular はコンポーネントクラスを渡します。引数の形だけが違い、呼び出し方は変わりません。

// いずれも it() の中に置きます

// Vue / Svelte
cy.mount(Stepper)

// Angular
cy.mount(StepperComponent)

cy.mount の実体は各フレームワーク用の mount 関数で、Reactなら import { mount } from 'cypress/react' で読み込めます。通常はCypressが初期設定時に cypress/support/component.{js,ts} へ登録コードを生成するため、自分で書く必要はありません。

propsの渡し方とイベント発火をcy.spyで検証する書き方

propsは第2引数、Reactだけは通常のJSX属性として渡します。表示の確認は cy.get で要素を取り、should で期待値と突き合わせます。

it('supports a "count" prop to set the value', () => {
  cy.mount(<Stepper count={100} />)
  cy.get('[data-cy=counter]').should('have.text', '100')
})

// 以下は it() の中に置く抜粋

// Vue / Svelte は props オプションで渡す
cy.mount(Stepper, { props: { count: 100 } })

// Angular は componentProperties
cy.mount(StepperComponent, { componentProperties: { count: 100 } })

イベントが正しい値で発火したかは、cy.spy() で作ったスパイをpropsとして渡し、エイリアス経由でアサーションします。モックの考え方自体はJestと共通なので、mockImplementation に慣れているならJest mockImplementationの使い方|戻り値・非同期・spyOn・requireActualの整理が参考になります。

it('clicking + fires a change event with the incremented value', () => {
  const onChangeSpy = cy.spy().as('onChangeSpy')
  cy.mount(<Stepper onChange={onChangeSpy} />)
  cy.get('[data-cy=increment]').click()
  cy.get('@onChangeSpy').should('have.been.calledWith', 1)
})

Provider付きコンポーネントのカスタムmountコマンド

React RouterのフックやReduxのストアを使うコンポーネントは、そのままマウントするとProviderが無く落ちます。毎回テスト側で包むのは手間なので、cy.mount 自体を上書きして共通のラッパーを持たせます。

// cypress/support/component.jsx
import { mount } from 'cypress/react'
import { MemoryRouter } from 'react-router-dom'

Cypress.Commands.add('mount', (component, options = {}) => {
  const { routerProps = { initialEntries: ['/'] }, ...mountOptions } = options
  const wrapped = <MemoryRouter {...routerProps}>{component}</MemoryRouter>
  return mount(wrapped, mountOptions)
})

この形にしておくと、テスト側からは初期URLだけを差し替えられます。ログイン後にだけ出るリンクの検証など、ルート依存の分岐を書き分けるときに効きます。

it('login link should be active when url is "/login"', () => {
  cy.mount(<Navigation />, { routerProps: { initialEntries: ['/login'] } })
  cy.get('a').contains('Login').should('have.class', 'active')
})

TypeScriptのプロジェクトでは、上書きした cy.mount の型を自分で宣言する必要があります。これを書かないと cy.mount が型エラーになり、追加した routerProps も補完されません。ウィザードが生成する component.ts には既定の宣言が入っていますが、引数を増やしたら合わせて更新してください。

// cypress/support/component.tsx
import { mount, MountOptions, MountReturn } from 'cypress/react'
import { MemoryRouter, MemoryRouterProps } from 'react-router-dom'

declare global {
  namespace Cypress {
    interface Chainable {
      mount(
        component: React.ReactNode,
        options?: MountOptions & { routerProps?: MemoryRouterProps }
      ): Cypress.Chainable<MountReturn>
    }
  }
}

Vueの場合は、PiniaやVue I18nといったプラグインを global.plugins に積む形になります。ラッパーコンポーネントで包むReactとは指定の仕方が違う点に注意してください。

// cypress/support/component.js
import { mount } from 'cypress/vue'
import { createPinia } from 'pinia'

Cypress.Commands.add('mount', (component, options = {}) => {
  options.global = options.global || {}
  options.global.plugins = options.global.plugins || []
  options.global.plugins.push(createPinia())
  return mount(component, options)
})

なお同じテスト内で cy.mount を続けて呼ぶと、Cypress 11.0.0以降は前回マウントしたコンポーネントがDOMから取り除かれます。2つの状態を並べて比較したい場合は、テストを分けてください。

cypress.configのdevServer設定とファイル形式の制約

導入自体はCypressアプリのウィザードが引き受けます。npm install -D cypress で入れて npx cypress open を実行し、テストの種類を選ぶ画面で「Component Testing」を選ぶと、フレームワークとバンドラを自動検出したうえで設定ファイル一式が生成されます。

生成される中で挙動を決めるのが component.devServer で、多くのプロジェクトはこの2行だけで足ります。

// cypress.config.mjs
import { defineConfig } from 'cypress'

export default defineConfig({
  component: {
    devServer: {
      framework: 'react', // 使用するUIフレームワーク
      bundler: 'vite',    // 'vite' または 'webpack'
    },
  },
})

ここでファイル形式に制約が入ります。バンドラにViteを使う場合、Cypress 15.0.0で @cypress/vite-dev-server がESM専用パッケージになったため、CommonJSからは読み込めません。require()module.exports で書いた cypress.config.js(package.jsonに "type": "module" が無い場合)や cypress.config.cjs は動きません。ファイル名を cypress.config.mjs にするか、package.jsonへ "type": "module" を足すか、TypeScript設定の cypress.config.ts を使ってください。バンドラがWebpackならこの制約はなく、CommonJS形式のままで動きます。

framework に書ける値は次の5つに限られます。コミュニティ製の定義(cypress-ct-* 形式のパッケージ)を除けば、これ以外の名前は受け付けません。

framework 指定できるbundler 対応バージョン 備考
react vite / webpack React 18-19
vue vite / webpack Vue 3
next webpack Next.js 14-16/React 18-19 Turbopackは未対応
angular webpack Angular 18-21 zone.js 0.14.0以上
svelte vite / webpack Svelte 5 Alpha

Next.js 16はTurbopackが既定のバンドラになりましたが、CypressのコンポーネントテストはNext.jsのコンポーネントをWebpackでバンドルしており、Turbopackにはまだ対応していません。Next.js 16のプロジェクトでも bundler: 'webpack' のままで構いません。

バンドラ側の対応版はViteが5〜8、Webpackが5です。Viteのプラグインやエイリアスは、Cypressが見つけた vite.config から読み込まれるため、独立した設定ファイルを置いているプロジェクトなら追加設定は要りません。設定ファイルが見つからない場合は、vite.config を用意するか viteConfig オプションを明示するよう促すエラーになります。

コンポーネントテストの実行コマンドとCI環境で回すときの書き分け

実行はE2Eテストと同じCLIで、コンポーネントテストを指定するフラグを付けます。対話的に確認したいときは open、CIで回すときは run です。

npx cypress open --component
npx cypress run --component

旧来の cypress open-ctcypress run-ct はCypress 14.0.0で削除されました。CIの設定ファイルに残っている場合は書き換えが必要です。

CIでは、実行対象のspecやブラウザを絞る指定を足していきます。--spec でファイルを限定し、--browser でブラウザを切り替え、Cypress Cloudへ記録するなら --record を付けます。プルリクエストごとにChromeで全件、夜間にFirefoxで全件といった配分が、実行時間と信頼性の折り合いとして扱いやすい形です。

npx cypress run --component --browser chrome --spec "cypress/components/**/*.cy.tsx"

もう1点、シェルコマンドの呼び出し方に注意点が増えました。15.21.0(2026年8月18日公開)で cy.exec() が非推奨になり、将来のメジャーリリースで削除される予定です。execTimeout も同時に非推奨扱いとなりました。テスト前後にDBの初期化スクリプトなどを走らせている場合は、OSやシェルに依存せずNode側で動く cy.task()taskTimeout への移し替えを、削除前に済ませておくと事故になりません。

data-cy属性を使ったセレクタ設計と属性名を統一しておく理由

cy.get('span') のようなタグ名指定は、コンポーネントに要素が1つ増えただけで壊れます。CSSクラスも見た目の変更で書き換わるため、テストの拠り所には向きません。そこで検証対象の要素にテスト専用の属性を付け、それを選択します。

<span data-cy="counter">{count}</span>

テスト側はCSSの属性セレクタで指定します。マークアップの入れ子やクラス名が変わっても、この属性さえ残っていればテストは壊れません。

// it() の中でのアサーション
cy.get('[data-cy=counter]').should('have.text', '0')

属性名はCypress公式のサンプルが data-cy を使う一方、Testing Library系のツールは data-testid を既定にしています。どちらでも動作は同じで、CypressはCSS属性セレクタとして解釈するだけです。選ぶ基準は好みではなく、プロジェクト内で1種類に統一されているかどうかです。2種類が混在すると、要素を追加するたびにどちらを付けるべきか迷い、付け忘れた要素がテストから漏れます。他のテストツールを併用しているなら、そちらが既定にしている属性へ寄せてください。ゼロから始めるCypress単独のプロジェクトなら、公式サンプルに合わせて data-cy を既定にすれば迷いません。

Cypress 14・15で削除された対応環境と移行時の注意点

コンポーネントテストの解説記事は2022年前後に多く書かれましたが、その多くが現行版では動きません。2025年1月16日公開のCypress 14.0.0が対応フレームワークとバンドラをまとめて整理し、同年8月20日公開の15.0.0がさらに最小バージョンを引き上げたためです。古い手順を踏襲する前に、ここを確認してください。

create-react-app・Vue CLI・Vue 2の打ち切り

Cypress 14.0.0のBreaking Changesは、コンポーネントテストが以下をサポートしなくなったと明記しています。

  • create-react-app、@vue/cli-service(Vue CLI)
  • Vue 2、React 16および17
  • Next.js 10〜13、Nuxt.js 2
  • Angular 13〜16(14.0.0時点の最小対応はシグナル対応のため17.2.0)、Svelte 3および4

これらを使っているプロジェクトでは、Cypressを14以降へ上げる前にバンドラの移行が先です。create-react-app前提のReactアプリなら、ViteかWebpack 5構成へ移したうえでコンポーネントテストを導入することになります。新規にcreate-react-appのままCypressのコンポーネントテストを組む選択肢は、現行版では成立しません。

cypress/react18の廃止とReact 19への対応追加

React 18向けに分かれていた cypress/react18 は、14.0.0でCypressバイナリから外れました。React 18のサポートは cypress/react に統合されているため、importパスを from 'cypress/react18' から from 'cypress/react' へ書き換えます。npm上の @cypress/react18 パッケージも2.0.1(2024年6月7日公開)を最後に非推奨扱いです。

同じ14.0.0でReact 19のコンポーネントテスト対応が追加され、v15の公式対応はReact 18と19の2系統になりました。一方で16と17は同時に打ち切られているため、React 17以下のプロジェクトはCypress 13以前に留まるか、Reactのメジャーアップグレードが先になります。Angularでも同様の統合があり、cypress/angular-signalscypress/angular へまとめられ、rxjs をpeerDependencyとして要求します。

Cypress 15で上がった最小バージョンとESM化の要件

15.0.0はコンポーネントテスト周りをさらに絞り込みました。v14で通っていた構成が、15へ上げた途端に動かなくなる項目が含まれます。

  • Angular 17のサポートを終了。最小対応は18.0.0(Angular 17のLTS終了に合わせた変更)
  • @cypress/vite-dev-server がESM専用化。Vite 4のサポートも終了し最小は5
  • @cypress/angular が要求する zone.js の最小版が0.14.0に
  • 設定ウィザードが対応するTypeScriptは5.0以上
  • Node.js 18と23のサポートを削除(15.21.1が要求する範囲は ^20.1.0 || ^22.0.0 || >=24.0.0

Angular 18へすぐ上げられない場合の逃げ道は公式に用意されています。npmから @cypress/angular@3 を個別に入れ、サポートファイルのimport元を from 'cypress/angular' から from '@cypress/angular' へ書き換える方法です。ただしこのテストハーネスは非推奨でCypressのサポート対象外なので、Angular 18へ移行するまでの一時しのぎと考えてください。

Nuxtなどメタフレームワークで起きるエイリアス解決の失敗と対処

Nuxtのようにフレームワーク自身がVite設定を内部生成するタイプでは、コンポーネントの import Button from '@/components/Button' が解決できず、モジュールが見つからない旨のコンパイルエラーで落ちます。Cypressが読むのは発見できた vite.configwebpack.config だけで、nuxt.config を実行して設定を取り出すことはしないためです。

対処は、必要なエイリアスを viteConfig に明示することです。渡した内容はCypress側の設定にマージされるため、コンポーネントが実際に使っているエイリアスだけ書けば足ります。下の例はバンドラがViteなので、前述のとおり設定ファイル自体をESMコンテキストに置く必要があります。import.meta.url もESMでしか使えません。

// cypress.config.mjs (ESM)
import { defineConfig } from 'cypress'
import { fileURLToPath } from 'url'

export default defineConfig({
  component: {
    devServer: {
      framework: 'vue',
      bundler: 'vite',
      viteConfig: {
        resolve: {
          alias: {
            '@': fileURLToPath(new URL('./', import.meta.url)),
            '~': fileURLToPath(new URL('./', import.meta.url)),
          },
        },
      },
    },
  },
})

同じ理屈で、tsconfig.jsoncompilerOptions.paths に書いただけのエイリアスも解決されません。これは型チェック用の設定で、ViteもWebpackもバンドル時には読まないからです。パス解決用のプラグインを、Cypressへ渡す設定側に追加してください。

justInTimeCompileによるコンパイル範囲の変更

14.0.0で justInTimeCompile が既定で有効になりました。実行するspecに直接関係するリソースだけを、spec実行の直前にコンパイルする挙動です。テスト件数の多いプロジェクトほどメモリ消費と待ち時間に効きますが、対象はWebpackのみで、Viteには適用されません。

Cypressの導入を決める条件と別ツールへ振ったほうがよい場面

既存スタックから見てCypressを採用してよいと言える条件

ここまでの制約と特性を踏まえると、採用してよい条件は絞り込めます。次の4つが揃っているなら、Cypressで着地させて構いません。

  • テストを書くのがフロントエンドの実装者で、JavaScriptまたはTypeScriptが共通言語になっている
  • 検証対象が自社アプリ1つで、ドメインをまたぐ操作が認証リダイレクト程度に収まる
  • 2ブラウザ同時操作・複数タブ・ネイティブアプリ連携が要件に入っていない
  • フレームワークとNode.jsのバージョンが、v15の対応範囲(React 18-19、Vue 3、Angular 18-21、Next.js 14-16、Node.js 20系以上)に収まっている

逆に言えば、4つ目が満たせないプロジェクトは、Cypressの導入より先にフロントエンドの版上げを片付ける順序になります。React 17のまま残っているアプリにCypress 15を入れる回り道より、Reactのメジャーアップグレードを終えてから入れるほうが総工数は小さく収まります。

PlaywrightやSeleniumのほうが向く場面の見分け方

見送る判断も条件で言い切れます。チャットやビデオ会議のように2ユーザーの相互作用を同一テストで検証したい、外部SaaSの管理画面を横断して操作したい、テスト担当者の主言語がJavaやPythonである。このいずれかに当たるなら、Playwrightまたは Selenium を先に検討してください。Cypressで書けないわけではなく、回避策の保守コストが積み上がる形になります。

また、テストランナーをすでにVitestで統一しているなら、ブラウザ上のコンポーネント検証もVitest側に寄せる選択肢があります。設定と実行系を一本化できるぶん学習コストが下がるためで、現状の書き方はVitestの使い方|React Testing Libraryでコンポーネントテストを書く実践ガイド【2026年版】に整理しました。

テスト自動化基盤を内製で回すか外部の手を借りるかを決める判断軸

ツール選定より難しいのは、書いたテストを誰が維持するかです。テストコードはアプリの変更に追従して直し続ける対象で、放置すると失敗が常態化し、やがて誰も結果を見なくなります。CIが赤いまま放置されている現場では、ツールを入れ替えても同じ結末をたどります。

判断軸は3つです。第一に、テストの追加と修正を担当する人が固定で確保できるか。第二に、フレームワークのメジャー更新(Angular 17→18のような)に追随する時間を年間の計画へ織り込めるか。第三に、CIの実行時間とCloudの費用を誰が見るか。ここが曖昧なまま導入すると、半年後には形骸化した資産が残ります。

一創では、テスト基盤の初期構築から運用の引き継ぎまでを含めた保守運用・内製化支援を行っています。CypressのCI組み込みや不安定なテストの整理を外部で回しつつ、社内メンバーへ運用を移していく進め方に対応できますので、体制づくりの段階で行き詰まっている場合はご相談ください。

よくある質問

Cypressとは何をするツールですか。
ブラウザで動くWebアプリを対象としたテスト実行基盤です。E2Eテスト・コンポーネントテスト・APIテストを1つのアプリで扱い、テストコードをアプリと同じブラウザの中で走らせます。この構造から、要素の出現待ちが自動で行われ、実行後にコマンド単位でDOMスナップショットへ戻れるデバッグ体験が生まれます。

Cypressは無料で使えますか。
テストを書いて実行するCypress AppはMITライセンスのオープンソースで、ローカルでもCIでも無償です。費用が発生するのは、実行結果の記録・並列化・分析を担うCypress Cloudを使う場合になります。Cloudにも無償のStarterプランがあり、2026年8月時点では月500テスト結果までが枠として示されていました。

CypressとSeleniumの違いはどこですか。
実行位置が決定的な差です。SeleniumはWebDriverプロトコル越しに外からブラウザを操作する方式で、言語もブラウザも幅広い選択肢から選べる構成です。Cypressはブラウザの中でテストを走らせるためJavaScriptとTypeScriptに限られる代わりに、自動リトライとスナップショット付きのデバッグを標準で持ちます。複数タブや2ブラウザ同時操作が必要ならSelenium側が向きます。

cy.mountはどこからimportすればよいですか。
通常はimport不要です。初期設定時にCypressが cypress/support/component.{js,ts} を生成し、そこで import { mount } from 'cypress/react'Cypress.Commands.add('mount', mount) を登録するため、テストファイルからは cy.mount をそのまま呼べます。Providerで包むなど独自化したい場合だけ、この登録部分を書き換えます。

data-cyとdata-testidはどちらを使うべきですか。
動作上の違いはなく、どちらもCSS属性セレクタとして扱われます。Cypress公式のサンプルは data-cy、Testing Library系は data-testid が既定です。既存のテスト資産がある側に統一し、ゼロから始めるCypress単独のプロジェクトなら data-cy を既定にしてください。

コンポーネントテストとE2Eテストはどちらから書くべきですか。
実行時間が短く原因の特定が容易なコンポーネントテストを厚くし、E2Eテストは主要な業務フローに絞るのが基本形です。ただしNext.jsのページのようにサーバ側の処理を含むものは、コンポーネントテストでは検証できないためE2Eテスト側で扱います。

create-react-appのプロジェクトでコンポーネントテストは動きますか。
Cypress 13以前なら動作しますが、14.0.0でcreate-react-appのサポートは削除されました。現行版で使うにはViteまたはWebpack 5の構成へ移行する必要があります。

Nuxtでimportが解決できずspecがコンパイルできません。
CypressはNuxtの設定ファイルを実行しないため、Nuxtが提供する @~ のエイリアスを認識できません。devServer.viteConfigresolve.alias に必要なエイリアスを明示してください。

関連記事

資料請求

RELATED POSTS 関連記事