Skip to content

作業履歴 2025-06-10

概要

2025-06-10の作業内容をまとめています。このジャーナルでは、E2Eテスト環境の構築と実装に関する作業を記録しています。

システム構成図

uml diagram

作業内容

E2Eテスト環境の構築

E2Eテスト(End-to-End テスト)は、アプリケーションの全体的な機能を検証するために重要です。今回の作業では、Capybaraとselenium-webdriverを使用したE2Eテスト環境を整備しました。

変更点の概要

  1. テスト用の設定ファイルの修正
  2. テストデータのファクトリ設定の更新
  3. プログラム管理機能のE2Eテストの実装

技術的詳細

uml diagram

コミット: 75931b2

メッセージ

test(WIP):E2Eテスト

変更されたファイル

  • M config/locales/views/ja.yml
  • M spec/factories/entries.rb
  • M spec/features/staff/program_management_spec.rb

変更内容

commit 75931b26d769263f0e5169e1294146d410fa5795
Author: k2works <kakimomokuri@gmail.com>
Date:   Tue Jun 10 18:10:48 2025 +0900

    test(WIP):E2Eテスト

diff --git a/config/locales/views/ja.yml b/config/locales/views/ja.yml
index 94c8e8f..a7d03e1 100644
--- a/config/locales/views/ja.yml
+++ b/config/locales/views/ja.yml
@@ -120,7 +120,7 @@ ja:
         program_start: '申し込み開始日時'
         program_end: '申し込み終了日時'
         program_min_entry: '最小参加者数'
-        program_max_entry: '最大参観者数'
+        program_max_entry: '最大参加者数'
         program_entry_count: '申し込み件数'
         program_staff: '登録職員'
         action: 'アクション'
@@ -130,7 +130,7 @@ ja:
         program_start: '申し込み開始日時'
         program_end: '申し込み終了日時'
         program_min_entry: '最小参加者数'
-        program_max_entry: '最大参観者数'
+        program_max_entry: '最大参加者数'
         program_entry_count: '申し込み件数'
         program_staff: '登録職員'
       new:
@@ -151,7 +151,7 @@ ja:
         program_end: '申し込み終了日時'
         program_end_instruction: '開始日時から90日後まで'
         program_min_entry: '最小参加者数'
-        program_max_entry: '最大参観者数'
+        program_max_entry: '最大参加者数'
       entries_form:
         name: '氏名'
         a: 'A'
diff --git a/spec/factories/entries.rb b/spec/factories/entries.rb
index 68decf9..6dc2a58 100644
--- a/spec/factories/entries.rb
+++ b/spec/factories/entries.rb
@@ -19,6 +19,9 @@

 FactoryBot.define do
   factory :entry do
-    
+    program
+    customer
+    approved { false }
+    canceled { false }
   end
 end
diff --git a/spec/features/staff/program_management_spec.rb b/spec/features/staff/program_management_spec.rb
index 413731f..190110a 100644
--- a/spec/features/staff/program_management_spec.rb
+++ b/spec/features/staff/program_management_spec.rb
@@ -1,35 +1,82 @@
 require 'rails_helper'

-feature 'プログラム管理機能', :performace do
+feature '職員によるプログラム管理' do
   include FeaturesSpecHelper
   include PerformanceSpecHelper
   let(:staff_member) { create(:staff_member) }
+  let!(:program) { create(:program, registrant: staff_member) }
+  let(:customer) { create(:customer) }
+  let!(:entry) { create(:entry, program: program, customer: customer) }

   before do
-    20.times do |n|
-      p  = create(:program, application_start_time: n.days.ago.midnight)
-      if n < 2
-        p.applicants << create(:customer)
-        p.applicants << create(:customer)
-      end
-    end
-
     switch_namespace(:staff)
     login_as_staff_member(staff_member)
   end

-  scenario 'プログラム一覧' do |example|
+  scenario '職員がプログラム一覧を表示する' do
     visit staff_programs_path
     expect(page).to have_css('h1', text: I18n.t('staff.programs.index.title'))
+    expect(page).to have_content(program.title)
+  end
+
+  scenario '職員がプログラム詳細を表示する' do
+    visit staff_programs_path
+    click_link I18n.t('staff.programs.form.show')
+
+    expect(page).to have_content(program.title)
+    expect(page).to have_content(program.description)
+  end

-    elapsed = Benchmark.realtime do
-      100.times do
-        visit staff_programs_path
-      end
-    end
+  scenario '職員が新規プログラムを登録する' do
+    visit staff_programs_path
+    first('a', text: I18n.t('staff.programs.index.new')).click
+
+    fill_in I18n.t('activerecord.attributes.program.title'), with: 'New Program'
+    fill_in I18n.t('activerecord.attributes.program.description'), with: 'Program Description'
+    fill_in I18n.t('activerecord.attributes.program.application_start_date'), with: Date.today.to_s
+    select '09', from: "form_program_application_start_hour"
+    select '00', from: "form_program_application_start_minute"
+    fill_in I18n.t('activerecord.attributes.program.application_end_date'), with: Date.today.next_month.to_s
+    select '17', from: "form_program_application_end_hour"
+    select '00', from: "form_program_application_end_minute"
+    fill_in I18n.t('activerecord.attributes.program.min_number_of_participants'), with: '5'
+    fill_in I18n.t('activerecord.attributes.program.max_number_of_participants'), with: '10'
+
+    click_button I18n.t('staff.programs.new.create')

-    write_to_performance_log(example, elapsed)
-    expect(elapsed).to be < 100.0
+    expect(page).to have_css('.Flash__notice', text: I18n.t('staff.programs.create.flash_notice'))
+    expect(Program.find_by(title: 'New Program')).to be_present
   end

+  scenario '職員がプログラムを編集する' do
+    visit staff_programs_path
+    click_link I18n.t('staff.programs.form.edit')
+
+    fill_in I18n.t('activerecord.attributes.program.title'), with: 'Updated Program'
+    click_button I18n.t('staff.programs.edit.update')
+
+    expect(page).to have_css('.Flash__notice', text: I18n.t('staff.programs.update.flash_notice'))
+    expect(program.reload.title).to eq('Updated Program')
+  end
+
+  scenario '職員がプログラムを削除する' do
+    program_without_entries = create(:program, registrant: staff_member)
+
+    visit staff_programs_path
+
+    all('a', text: I18n.t('staff.programs.form.delete')).last.click
+
+    expect(page).to have_css('.Flash__notice', text: I18n.t('staff.programs.destroy.flash_notice'))
+    expect(Program.find_by(id: program_without_entries.id)).to be_nil
+  end
+
+  scenario '職員がエントリーを管理する' do
+    visit staff_program_path(program)
+
+    find("input[type='checkbox'].isApproved[data-entry-id='#{entry.id}']").click
+    click_button I18n.t('staff.programs.entries_form.update')
+
+    expect(page).to have_css('.Flash__notice', text: I18n.t('staff.programs.entries.flash_notice'))
+    expect(entry.reload.approved).to be true
+  end
 end

コミット: 00e4601

メッセージ

test(WIP):E2Eテスト

変更されたファイル

  • M app/controllers/customer/programs_controller.rb
  • M spec/features/customer/program_management_spec.rb

変更内容

commit 00e4601c979a9c5b18e48f66a032ba5464f00149
Author: k2works <kakimomokuri@gmail.com>
Date:   Tue Jun 10 16:35:12 2025 +0900

    test(WIP):E2Eテスト

diff --git a/app/controllers/customer/programs_controller.rb b/app/controllers/customer/programs_controller.rb
index 0cf4a1e..c6d8421 100644
--- a/app/controllers/customer/programs_controller.rb
+++ b/app/controllers/customer/programs_controller.rb
@@ -4,6 +4,6 @@ class Customer::ProgramsController < Customer::Base
   end

   def show
-    @program = Program.published.find(params[:id])
+    @program = Program.published.find_by(params[:id])
   end
 end
diff --git a/spec/features/customer/program_management_spec.rb b/spec/features/customer/program_management_spec.rb
index 8341e2d..a2230b8 100644
--- a/spec/features/customer/program_management_spec.rb
+++ b/spec/features/customer/program_management_spec.rb
@@ -19,50 +19,37 @@ feature '顧客によるプログラム管理' do

   scenario '顧客がプログラム詳細を閲覧する' do
     visit customer_programs_path
-    click_link program.title
-    
-    expect(page).to have_css('h1', text: program.title)
+    click_link I18n.t('staff.programs.form.show')
+
+    expect(page).to have_content(program.title)
     expect(page).to have_content(program.description)
   end

   scenario '顧客がプログラムを予約する' do
     visit customer_program_path(program)
-    click_link I18n.t('customer.programs.show.apply')
-    
-    fill_in I18n.t('activerecord.attributes.entry.remarks'), with: 'テスト予約'
-    click_button I18n.t('customer.entries.new.submit')
+    click_button I18n.t('customer.programs.show.apply')

-    expect(page).to have_css('.notice', text: I18n.t('customer.entries.create.notice'))
+    expect(page).to have_css('.Flash__notice', text: I18n.t('customer.entries.create.flash_notice'))
     expect(Entry.find_by(program: program, customer: customer)).to be_present
   end

   scenario '顧客が予約をキャンセルする' do
-    entry = create(:entry, program: program, customer: customer)
-    
-    visit customer_entries_path
-    click_link program.title
-    click_link I18n.t('customer.entries.show.cancel')
-    
-    expect(page).to have_css('.notice', text: I18n.t('customer.entries.cancel.notice'))
-    expect(entry.reload.canceled).to be_truthy
+    visit customer_program_path(program)
+    click_button I18n.t('customer.programs.show.apply')
+    visit customer_program_path(program)
+    click_button I18n.t('customer.programs.show.cancel')
+
+    expect(page).to have_css('.Flash__notice', text: I18n.t('customer.entries.cancel.flash_notice'))
+    expect(Entry.find_by(program: program, customer: customer).canceled).to be true
   end

   scenario '顧客が予約期間外のプログラムを予約しようとする' do
-    closed_program = create(:program, application_start_time: 10.days.from_now, application_end_time: 20.days.from_now)
-    
-    visit customer_program_path(closed_program)
-    
-    expect(page).not_to have_link(I18n.t('customer.programs.show.apply'))
-    expect(page).to have_content(I18n.t('customer.programs.show.not_applicable'))
-  end
+    Program.delete_all
+    closed_program = create(:program, application_start_time: 20.days.ago, application_end_time: 10.days.ago)
+    visit customer_programs_path

-  scenario '顧客が定員超過のプログラムを予約しようとする' do
-    full_program = create(:program, application_start_time: 2.days.ago, application_end_time: 2.days.from_now, max_number_of_participants: 1)
-    create(:entry, program: full_program) # Fill the program
-    
-    visit customer_program_path(full_program)
+    visit customer_program_path(closed_program)

-    expect(page).not_to have_link(I18n.t('customer.programs.show.apply'))
-    expect(page).to have_content(I18n.t('customer.programs.show.full'))
+    expect(page).to have_button(I18n.t('customer.programs.show.closed'), disabled: true)
   end
 end
\ No newline at end of file

構造変更

uml diagram

コミット: 429998b

メッセージ

docs:ユースケース更新

変更されたファイル

  • M "docs/\343\203\246\343\203\274\343\202\271\343\202\261\343\203\274\343\202\271.md"

変更内容

commit 429998be7be58147cc12ad325bbfd790bd33b9bb
Author: k2works <kakimomokuri@gmail.com>
Date:   Tue Jun 10 15:21:20 2025 +0900

    docs:ユースケース更新

diff --git "a/docs/\343\203\246\343\203\274\343\202\271\343\202\261\343\203\274\343\202\271.md" "b/docs/\343\203\246\343\203\274\343\202\271\343\202\261\343\203\274\343\202\271.md"
index 8d89046..51eb39c 100644
--- "a/docs/\343\203\246\343\203\274\343\202\271\343\202\261\343\203\274\343\202\271.md"
+++ "b/docs/\343\203\246\343\203\274\343\202\271\343\202\261\343\203\274\343\202\271.md"
@@ -2,58 +2,58 @@

 ## 1. 概要

-このドキュメントはBaukis-Kaiシステムの主要なユースケースを定義します。システムは主に3つのユーザータイプ(スタッフ、顧客、管理者)向けの機能を提供しています。
+このドキュメントはBaukis-Kaiシステムの主要なユースケースを定義します。システムは主に3つのユーザータイプ(職員、顧客、管理者)向けの機能を提供しています。

 ## 2. アクター定義

 システムには以下の主要なアクターが存在します:

-1. **スタッフ**: 顧客情報管理、プログラム管理、顧客とのコミュニケーションを担当する組織の従業員
+1. **職員**: 顧客情報管理、プログラム管理、顧客とのコミュニケーションを担当する組織の従業員
 2. **顧客**: サービスを利用する個人またはグループ
-3. **管理者**: システム全体とスタッフアカウントを管理する権限を持つユーザー
+3. **管理者**: システム全体と職員アカウントを管理する権限を持つユーザー

-## 3. スタッフのユースケース
+## 3. 職員のユースケース

 ### 3.1. アカウント管理

 | ユースケースID | S-001 |
 | ------------- | ----- |
-| ユースケース名 | スタッフログイン |
-| アクター | スタッフ |
-| 説明 | スタッフがシステムにログインする |
-| 事前条件 | スタッフアカウントが作成されている |
-| 基本フロー | 1. スタッフがログインページにアクセス<br>2. メールアドレスとパスワードを入力<br>3. 認証情報を検証<br>4. ダッシュボードにリダイレクト |
+| ユースケース名 | 職員ログイン |
+| アクター | 職員 |
+| 説明 | 職員がシステムにログインする |
+| 事前条件 | 職員アカウントが作成されている |
+| 基本フロー | 1. 職員がログインページにアクセス<br>2. メールアドレスとパスワードを入力<br>3. 認証情報を検証<br>4. ダッシュボードにリダイレクト |
 | 代替フロー | - 認証失敗: エラーメッセージを表示<br>- アカウント停止中: アクセス拒否メッセージを表示 |
-| 事後条件 | スタッフがシステムにログインした状態になる |
+| 事後条件 | 職員がシステムにログインした状態になる |

 | ユースケースID | S-002 |
 | ------------- | ----- |
-| ユースケース名 | スタッフログアウト |
-| アクター | スタッフ |
-| 説明 | スタッフがシステムからログアウトする |
-| 事前条件 | スタッフがログイン済み |
-| 基本フロー | 1. スタッフがログアウトボタンをクリック<br>2. セッションを終了<br>3. ログインページにリダイレクト |
+| ユースケース名 | 職員ログアウト |
+| アクター | 職員 |
+| 説明 | 職員がシステムからログアウトする |
+| 事前条件 | 職員がログイン済み |
+| 基本フロー | 1. 職員がログアウトボタンをクリック<br>2. セッションを終了<br>3. ログインページにリダイレクト |
 | 代替フロー | なし |
-| 事後条件 | スタッフがログアウト状態になる |
+| 事後条件 | 職員がログアウト状態になる |

 | ユースケースID | S-003 |
 | ------------- | ----- |
-| ユースケース名 | スタッフアカウント情報更新 |
-| アクター | スタッフ |
-| 説明 | スタッフが自身のアカウント情報を更新する |
-| 事前条件 | スタッフがログイン済み |
-| 基本フロー | 1. スタッフがアカウント設定ページにアクセス<br>2. 情報を編集<br>3. 変更を保存 |
+| ユースケース名 | 職員アカウント情報更新 |
+| アクター | 職員 |
+| 説明 | 職員が自身のアカウント情報を更新する |
+| 事前条件 | 職員がログイン済み |
+| 基本フロー | 1. 職員がアカウント設定ページにアクセス<br>2. 情報を編集<br>3. 変更を保存 |
 | 代替フロー | - バリデーションエラー: エラーメッセージを表示し再編集を促す |
-| 事後条件 | スタッフの情報が更新される |
+| 事後条件 | 職員の情報が更新される |

 ### 3.2. 顧客管理

 | ユースケースID | S-004 |
 | ------------- | ----- |
 | ユースケース名 | 顧客情報登録 |
-| アクター | スタッフ |
-| 説明 | スタッフが新規顧客情報を登録する |
-| 事前条件 | スタッフがログイン済み |
+| アクター | 職員 |
+| 説明 | 職員が新規顧客情報を登録する |
+| 事前条件 | 職員がログイン済み |
 | 基本フロー | 1. 顧客登録フォームにアクセス<br>2. 顧客の基本情報を入力<br>3. 住所情報を入力(自宅/職場)<br>4. 電話番号情報を入力<br>5. フォームを送信<br>6. システムがデータを検証<br>7. 顧客情報を保存 |
 | 代替フロー | - バリデーションエラー: エラーメッセージを表示し再編集を促す |
 | 事後条件 | 新規顧客情報がシステムに登録される |
@@ -61,9 +61,9 @@
 | ユースケースID | S-005 |
 | ------------- | ----- |
 | ユースケース名 | 顧客情報検索 |
-| アクター | スタッフ |
-| 説明 | スタッフが顧客情報を検索する |
-| 事前条件 | スタッフがログイン済み |
+| アクター | 職員 |
+| 説明 | 職員が顧客情報を検索する |
+| 事前条件 | 職員がログイン済み |
 | 基本フロー | 1. 顧客検索フォームにアクセス<br>2. 検索条件(名前、メールアドレス、電話番号など)を入力<br>3. 検索を実行<br>4. 検索結果を表示 |
 | 代替フロー | - 検索結果なし: 該当する顧客がない旨のメッセージを表示 |
 | 事後条件 | 検索条件に合致する顧客情報が表示される |
@@ -71,9 +71,9 @@
 | ユースケースID | S-006 |
 | ------------- | ----- |
 | ユースケース名 | 顧客情報更新 |
-| アクター | スタッフ |
-| 説明 | スタッフが既存の顧客情報を更新する |
-| 事前条件 | スタッフがログイン済み、顧客が登録済み |
+| アクター | 職員 |
+| 説明 | 職員が既存の顧客情報を更新する |
+| 事前条件 | 職員がログイン済み、顧客が登録済み |
 | 基本フロー | 1. 顧客詳細ページにアクセス<br>2. 編集ボタンをクリック<br>3. 顧客情報を編集<br>4. 変更を保存 |
 | 代替フロー | - バリデーションエラー: エラーメッセージを表示し再編集を促す |
 | 事後条件 | 顧客情報が更新される |
@@ -83,9 +83,9 @@
 | ユースケースID | S-007 |
 | ------------- | ----- |
 | ユースケース名 | プログラム作成 |
-| アクター | スタッフ |
-| 説明 | スタッフが新規プログラムを作成する |
-| 事前条件 | スタッフがログイン済み |
+| アクター | 職員 |
+| 説明 | 職員が新規プログラムを作成する |
+| 事前条件 | 職員がログイン済み |
 | 基本フロー | 1. プログラム作成フォームにアクセス<br>2. プログラム詳細(タイトル、説明、日時、参加人数制限等)を入力<br>3. フォームを送信<br>4. システムがデータを検証<br>5. プログラム情報を保存 |
 | 代替フロー | - バリデーションエラー: エラーメッセージを表示し再編集を促す |
 | 事後条件 | 新規プログラムがシステムに登録される |
@@ -93,9 +93,9 @@
 | ユースケースID | S-008 |
 | ------------- | ----- |
 | ユースケース名 | プログラム更新 |
-| アクター | スタッフ |
-| 説明 | スタッフが既存のプログラム情報を更新する |
-| 事前条件 | スタッフがログイン済み、プログラムが登録済み |
+| アクター | 職員 |
+| 説明 | 職員が既存のプログラム情報を更新する |
+| 事前条件 | 職員がログイン済み、プログラムが登録済み |
 | 基本フロー | 1. プログラム詳細ページにアクセス<br>2. 編集ボタンをクリック<br>3. プログラム情報を編集<br>4. 変更を保存 |
 | 代替フロー | - バリデーションエラー: エラーメッセージを表示し再編集を促す<br>- 既に予約がある場合: 特定の項目の編集を制限 |
 | 事後条件 | プログラム情報が更新される |
@@ -103,9 +103,9 @@
 | ユースケースID | S-009 |
 | ------------- | ----- |
 | ユースケース名 | プログラム参加者管理 |
-| アクター | スタッフ |
-| 説明 | スタッフがプログラムの参加者を管理する |
-| 事前条件 | スタッフがログイン済み、プログラムが登録済み |
+| アクター | 職員 |
+| 説明 | 職員がプログラムの参加者を管理する |
+| 事前条件 | 職員がログイン済み、プログラムが登録済み |
 | 基本フロー | 1. プログラム詳細ページの参加者タブにアクセス<br>2. 参加者リストを確認<br>3. 参加承認または拒否の操作を行う |
 | 代替フロー | - 参加者なし: 参加者がいない旨のメッセージを表示 |
 | 事後条件 | 参加者のステータスが更新される |
@@ -115,9 +115,9 @@
 | ユースケースID | S-010 |
 | ------------- | ----- |
 | ユースケース名 | 顧客への問い合わせ送信 |
-| アクター | スタッフ |
-| 説明 | スタッフが顧客にメッセージを送信する |
-| 事前条件 | スタッフがログイン済み、顧客が登録済み |
+| アクター | 職員 |
+| 説明 | 職員が顧客にメッセージを送信する |
+| 事前条件 | 職員がログイン済み、顧客が登録済み |
 | 基本フロー | 1. 顧客詳細ページのメッセージタブにアクセス<br>2. 新規メッセージボタンをクリック<br>3. メッセージのタイトルと本文を入力<br>4. タグを選択(オプション)<br>5. メッセージを送信 |
 | 代替フロー | - バリデーションエラー: エラーメッセージを表示し再編集を促す |
 | 事後条件 | メッセージが顧客に送信される |
@@ -125,9 +125,9 @@
 | ユースケースID | S-011 |
 | ------------- | ----- |
 | ユースケース名 | 顧客からの問い合わせ確認 |
-| アクター | スタッフ |
-| 説明 | スタッフが顧客からのメッセージを確認する |
-| 事前条件 | スタッフがログイン済み、顧客からメッセージが送信済み |
+| アクター | 職員 |
+| 説明 | 職員が顧客からのメッセージを確認する |
+| 事前条件 | 職員がログイン済み、顧客からメッセージが送信済み |
 | 基本フロー | 1. メッセージ一覧ページにアクセス<br>2. 未読または特定の顧客からのメッセージをフィルタ<br>3. メッセージを選択して詳細を閲覧 |
 | 代替フロー | - メッセージなし: メッセージがない旨のメッセージを表示 |
 | 事後条件 | メッセージが既読状態になる |
@@ -135,9 +135,9 @@
 | ユースケースID | S-012 |
 | ------------- | ----- |
 | ユースケース名 | 問い合わせ返信 |
-| アクター | スタッフ |
-| 説明 | スタッフが顧客のメッセージに返信する |
-| 事前条件 | スタッフがログイン済み、顧客からメッセージが送信済み |
+| アクター | 職員 |
+| 説明 | 職員が顧客のメッセージに返信する |
+| 事前条件 | 職員がログイン済み、顧客からメッセージが送信済み |
 | 基本フロー | 1. メッセージ詳細画面にアクセス<br>2. 返信ボタンをクリック<br>3. 返信内容を入力<br>4. 返信を送信 |
 | 代替フロー | - バリデーションエラー: エラーメッセージを表示し再編集を促す |
 | 事後条件 | 返信が顧客に送信される |
@@ -222,13 +222,13 @@

 | ユースケースID | C-008 |
 | ------------- | ----- |
-| ユースケース名 | スタッフへの問い合わせ送信 |
+| ユースケース名 | 職員への問い合わせ送信 |
 | アクター | 顧客 |
-| 説明 | 顧客がスタッフにメッセージを送信する |
+| 説明 | 顧客が職員にメッセージを送信する |
 | 事前条件 | 顧客がログイン済み |
-| 基本フロー | 1. マイページのメッセージ機能にアクセス<br>2. 新規メッセージボタンをクリック<br>3. メッセージのタイトルと本文を入力<br>4. 宛先のスタッフを選択またはカテゴリを選択<br>5. メッセージを送信 |
+| 基本フロー | 1. マイページのメッセージ機能にアクセス<br>2. 新規メッセージボタンをクリック<br>3. メッセージのタイトルと本文を入力<br>4. 宛先の職員を選択またはカテゴリを選択<br>5. メッセージを送信 |
 | 代替フロー | - バリデーションエラー: エラーメッセージを表示し再編集を促す |
-| 事後条件 | メッセージがスタッフに送信される |
+| 事後条件 | メッセージが職員に送信される |

 | ユースケースID | C-009 |
 | ------------- | ----- |
@@ -244,11 +244,11 @@
 | ------------- |---------------------------------------------------|
 | ユースケース名 | 問い合わせ返信                                           |
 | アクター | 顧客                                                |
-| 説明 | 顧客がスタッフのメッセージに返信する                                |
-| 事前条件 | 顧客がログイン済み、スタッフからメッセージが送信済み                        |
+| 説明 | 顧客が職員のメッセージに返信する                                |
+| 事前条件 | 顧客がログイン済み、職員からメッセージが送信済み                        |
 | 基本フロー | 1. マイページのメッセージ履歴にアクセス<br>2. メッセージスレッドを選択<br>3. 返信 |
 | 代替フロー | - バリデーションエラー: エラーメッセージを表示し再編集を促す                  |
-| 事後条件 | 返信がスタッフに送信される                                     |
+| 事後条件 | 返信が職員に送信される                                     |


 ## 5. 管理者のユースケース
@@ -275,62 +275,52 @@
 | 代替フロー | なし |
 | 事後条件 | 管理者がログアウト状態になる |

-### 5.2. スタッフ管理
+### 5.2. 職員管理

 | ユースケースID | A-003 |
 | ------------- | ----- |
-| ユースケース名 | スタッフアカウント作成 |
+| ユースケース名 | 職員アカウント作成 |
 | アクター | 管理者 |
-| 説明 | 管理者が新規スタッフアカウントを作成する |
+| 説明 | 管理者が新規職員アカウントを作成する |
 | 事前条件 | 管理者がログイン済み |
-| 基本フロー | 1. スタッフ管理ページにアクセス<br>2. 新規スタッフ作成ボタンをクリック<br>3. スタッフ情報を入力<br>4. アカウントを作成 |
+| 基本フロー | 1. 職員管理ページにアクセス<br>2. 新規スタッフ作成ボタンをクリック<br>3. スタッフ情報を入力<br>4. アカウントを作成 |
 | 代替フロー | - バリデーションエラー: エラーメッセージを表示し再編集を促す<br>- メールアドレス重複: エラーメッセージを表示 |
-| 事後条件 | 新規スタッフアカウントが作成される |
+| 事後条件 | 新規職員アカウントが作成される |

 | ユースケースID | A-004 |
 | ------------- | ----- |
-| ユースケース名 | スタッフアカウント編集 |
+| ユースケース名 | 職員アカウント編集 |
 | アクター | 管理者 |
-| 説明 | 管理者が既存のスタッフアカウント情報を編集する |
-| 事前条件 | 管理者がログイン済み、スタッフアカウントが存在する |
-| 基本フロー | 1. スタッフ一覧ページにアクセス<br>2. 編集するスタッフを選択<br>3. 編集ボタンをクリック<br>4. スタッフ情報を編集<br>5. 変更を保存 |
+| 説明 | 管理者が既存の職員アカウント情報を編集する |
+| 事前条件 | 管理者がログイン済み、職員アカウントが存在する |
+| 基本フロー | 1. 職員一覧ページにアクセス<br>2. 編集するスタッフを選択<br>3. 編集ボタンをクリック<br>4. スタッフ情報を編集<br>5. 変更を保存 |
 | 代替フロー | - バリデーションエラー: エラーメッセージを表示し再編集を促す |
-| 事後条件 | スタッフ情報が更新される |
+| 事後条件 | 職員情報が更新される |

 | ユースケースID | A-005 |
 | ------------- | ----- |
-| ユースケース名 | スタッフアカウント停止/再開 |
+| ユースケース名 | 職員アカウント停止/再開 |
 | アクター | 管理者 |
-| 説明 | 管理者がスタッフアカウントの停止または再開を行う |
-| 事前条件 | 管理者がログイン済み、スタッフアカウントが存在する |
-| 基本フロー | 1. スタッフ一覧ページにアクセス<br>2. 対象のスタッフを選択<br>3. 停止/再開ボタンをクリック<br>4. 確認ダイアログで確認 |
+| 説明 | 管理者が職員アカウントの停止または再開を行う |
+| 事前条件 | 管理者がログイン済み、職員アカウントが存在する |
+| 基本フロー | 1. 職員一覧ページにアクセス<br>2. 対象のスタッフを選択<br>3. 停止/再開ボタンをクリック<br>4. 確認ダイアログで確認 |
 | 代替フロー | なし |
-| 事後条件 | スタッフアカウントの状態が変更される |
+| 事後条件 | 職員アカウントの状態が変更される |

 | ユースケースID | A-006 |
 | ------------- | ----- |
-| ユースケース名 | スタッフイベントログ確認 |
+| ユースケース名 | 職員イベントログ確認 |
 | アクター | 管理者 |
-| 説明 | 管理者がスタッフのアクティビティログを確認する |
-| 事前条件 | 管理者がログイン済み、スタッフアカウントが存在する |
-| 基本フロー | 1. スタッフ詳細ページにアクセス<br>2. イベントログタブを選択<br>3. ログを閲覧 |
+| 説明 | 管理者が職員のアクティビティログを確認する |
+| 事前条件 | 管理者がログイン済み、職員アカウントが存在する |
+| 基本フロー | 1. 職員詳細ページにアクセス<br>2. イベントログタブを選択<br>3. ログを閲覧 |
 | 代替フロー | - ログなし: ログがない旨のメッセージを表示 |
-| 事後条件 | スタッフのアクティビティログが表示される |
+| 事後条件 | 職員のアクティビティログが表示される |

 ### 5.3. システム管理

 | ユースケースID | A-007 |
 | ------------- | ----- |
-| ユースケース名 | システム設定管理 |
-| アクター | 管理者 |
-| 説明 | 管理者がシステム全体の設定を管理する |
-| 事前条件 | 管理者がログイン済み |
-| 基本フロー | 1. システム設定ページにアクセス<br>2. 設定項目を編集<br>3. 変更を保存 |
-| 代替フロー | - バリデーションエラー: エラーメッセージを表示し再編集を促す |
-| 事後条件 | システム設定が更新される |
-
-| ユースケースID | A-008 |
-| ------------- | ----- |
 | ユースケース名 | アクセス制限IPアドレス管理 |
 | アクター | 管理者 |
 | 説明 | 管理者がアクセス許可するIPアドレスを管理する |
@@ -339,50 +329,6 @@
 | 代替フロー | - バリデーションエラー: エラーメッセージを表示し再編集を促す |
 | 事後条件 | アクセス制限設定が更新される |

-## 6. システム間ユースケース
-
-| ユースケースID | SYS-001 |
-| ------------- | ----- |
-| ユースケース名 | 自動メール送信 |
-| アクター | システム |
-| 説明 | システムが特定のイベント発生時に自動的にメールを送信する |
-| 事前条件 | 対象イベントが発生している(予約完了、メッセージ受信など) |
-| 基本フロー | 1. イベント発生を検知<br>2. メールテンプレートを選択<br>3. 必要な情報を埋め込む<br>4. メールを送信 |
-| 代替フロー | - メール送信失敗: エラーをログに記録し再送を試みる |
-| 事後条件 | メールが送信される |
-
-| ユースケースID | SYS-002 |
-| ------------- | ----- |
-| ユースケース名 | プログラム開始通知 |
-| アクター | システム |
-| 説明 | システムがプログラム開始前に参加者に通知する |
-| 事前条件 | プログラムが登録済み、参加者が存在する |
-| 基本フロー | 1. スケジュールされたタイミングで通知処理を実行<br>2. 参加者リストを取得<br>3. 各参加者に通知を送信 |
-| 代替フロー | - 通知送信失敗: エラーをログに記録 |
-| 事後条件 | 参加者に通知が送信される |
-
-## 7. 非機能要件に関連するユースケース
-
-| ユースケースID | NF-001 |
-| ------------- | ----- |
-| ユースケース名 | システム監視 |
-| アクター | 管理者 |
-| 説明 | 管理者がシステムのパフォーマンスと健全性を監視する |
-| 事前条件 | 管理者がログイン済み |
-| 基本フロー | 1. システム監視ダッシュボードにアクセス<br>2. パフォーマンス指標を確認<br>3. エラーログを確認<br>4. 必要に応じて対応策を実施 |
-| 代替フロー | なし |
-| 事後条件 | システム状態が把握される |
-
-| ユースケースID | NF-002 |
-| ------------- | ----- |
-| ユースケース名 | データバックアップ |
-| アクター | システム |
-| 説明 | システムが定期的にデータのバックアップを実行する |
-| 事前条件 | バックアップスケジュールが設定されている |
-| 基本フロー | 1. スケジュールされたタイミングでバックアッププロセスを開始<br>2. データベースのバックアップを取得<br>3. バックアップファイルを保存<br>4. 古いバックアップファイルの整理 |
-| 代替フロー | - バックアップ失敗: エラーをログに記録し管理者に通知 |
-| 事後条件 | データバックアップが作成される |
-
 ## 8. ユースケース関連図

 以下は、Baukis-Kaiシステムの主要なユースケースとアクター間の関係を示すUML図です。
@@ -401,15 +347,14 @@ skinparam usecase {
   ActorFontColor black
 }

-actor "スタッフ" as Staff
+actor "職員" as Staff
 actor "顧客" as Customer
 actor "管理者" as Admin
-actor "システム" as System

-rectangle "スタッフのユースケース" {
-  usecase "スタッフログイン" as S001
-  usecase "スタッフログアウト" as S002
-  usecase "スタッフアカウント情報更新" as S003
+rectangle "職員のユースケース" {
+  usecase "職員ログイン" as S001
+  usecase "職員ログアウト" as S002
+  usecase "職員アカウント情報更新" as S003
   usecase "顧客情報登録" as S004
   usecase "顧客情報検索" as S005
   usecase "顧客情報更新" as S006
@@ -429,30 +374,18 @@ rectangle "顧客のユースケース" {
   usecase "プログラム閲覧" as C005
   usecase "プログラム予約" as C006
   usecase "予約キャンセル" as C007
-  usecase "スタッフへの問い合わせ送信" as C008
+  usecase "職員への問い合わせ送信" as C008
   usecase "問い合わせ履歴確認" as C009
 }

 rectangle "管理者のユースケース" {
   usecase "管理者ログイン" as A001
   usecase "管理者ログアウト" as A002
-  usecase "スタッフアカウント作成" as A003
-  usecase "スタッフアカウント編���" as A004
-  usecase "スタッフアカウント停止/再開" as A005
-  usecase "スタッフイベントログ確認" as A006
-  usecase "システム設定管理" as A007
+  usecase "職員アカウント作成" as A003
+  usecase "職員アカウント編���" as A004
+  usecase "職員アカウント停止/再開" as A005
+  usecase "職員イベントログ確認" as A006
   usecase "アクセス制限IPアドレス管理" as A008
-  usecase "タグ管理" as A009
-}
-
-rectangle "システム間ユースケース" {
-  usecase "自動メール送信" as SYS001
-  usecase "プログラム開始通知" as SYS002
-}
-
-rectangle "非機能要件に関連するユースケース" {
-  usecase "システム監視" as NF001
-  usecase "データバックアップ" as NF002
 }

 Staff --> S001
@@ -468,15 +401,15 @@ Staff --> S010
 Staff --> S011
 Staff --> S012

-Customer --> C001
-Customer --> C002
-Customer --> C003
-Customer --> C004
-Customer --> C005
-Customer --> C006
-Customer --> C007
-Customer --> C008
-Customer --> C009
+C001 <-- Customer
+C002 <-- Customer
+C003 <-- Customer
+C004 <-- Customer
+C005 <-- Customer
+C006 <-- Customer
+C007 <-- Customer
+C008 <-- Customer
+C009 <-- Customer

 Admin --> A001
 Admin --> A002
@@ -484,14 +417,7 @@ Admin --> A003
 Admin --> A004
 Admin --> A005
 Admin --> A006
-Admin --> A007
 Admin --> A008
-Admin --> A009
-Admin --> NF001
-
-System --> SYS001
-System --> SYS002
-System --> NF002

 S010 ..> C009 : <<extend>>
 S011 ..> C008 : <<extend>>

コミット: 72de0b8

メッセージ

test(WIP):E2Eテスト

変更されたファイル

  • M spec/features/staff/message_management_spec.rb

変更内容

commit 72de0b863e8b81e58fea1eda5817d45b870cd569
Author: k2works <kakimomokuri@gmail.com>
Date:   Tue Jun 10 15:11:35 2025 +0900

    test(WIP):E2Eテスト

diff --git a/spec/features/staff/message_management_spec.rb b/spec/features/staff/message_management_spec.rb
index 18c6b9f..4561273 100644
--- a/spec/features/staff/message_management_spec.rb
+++ b/spec/features/staff/message_management_spec.rb
@@ -1,6 +1,6 @@
 require 'rails_helper'

-feature 'スタッフによるメッセージ管理' do
+feature '職員によるメッセージ管理' do
   include FeaturesSpecHelper
   include PerformanceSpecHelper
   let(:staff_member) { create(:staff_member) }
@@ -18,24 +18,24 @@ feature 'スタッフによるメッセージ管理' do
     login_as_staff_member(staff_member)
   end

-  scenario 'スタッフがメッセージ一覧を表示する' do
+  scenario '職員がメッセージ一覧を表示する' do
     visit staff_messages_path
     expect(page).to have_css('h1', text: I18n.t('staff.messages.index.title_index'))
     expect(page).to have_content('Hello')
   end

-  scenario 'スタッフが問い合わせ一覧を表示する' do
+  scenario '職員が問い合わせ一覧を表示する' do
     visit inbound_staff_messages_path
     expect(page).to have_css('h1', text: I18n.t('staff.messages.index.title_inbound'))
     expect(page).to have_content('Hello')
   end

-  scenario 'スタッフが返信一覧を表示する' do
+  scenario '職員が返信一覧を表示する' do
     visit outbound_staff_messages_path
     expect(page).to have_css('h1', text: I18n.t('staff.messages.index.title_outbound'))
   end

-  scenario 'スタッフが顧客からのメッセージに返信する' do
+  scenario '職員が顧客からのメッセージに返信する' do
     visit staff_message_path(root_message)
     within('.Table__links') do
       click_link I18n.t('staff.messages.show.reply')
@@ -50,7 +50,7 @@ feature 'スタッフによるメッセージ管理' do
     expect(StaffMessage.find_by(subject: 'Re: Hello', staff_member: staff_member)).to be_present
   end

-  scenario 'スタッフが問い合わせを削除する' do
+  scenario '職員が問い合わせを削除する' do
     visit staff_message_path(root_message)
     expect(page).to have_css('h1', text: 'メッセージ詳細')

コミット: 356390d

メッセージ

test(WIP):E2Eテスト

変更されたファイル

  • M spec/features/staff/message_management_spec.rb

変更内容

commit 356390d0a333a674270edff57e1a16cc9f1c0f22
Author: k2works <kakimomokuri@gmail.com>
Date:   Tue Jun 10 15:11:04 2025 +0900

    test(WIP):E2Eテスト

diff --git a/spec/features/staff/message_management_spec.rb b/spec/features/staff/message_management_spec.rb
index 763d243..18c6b9f 100644
--- a/spec/features/staff/message_management_spec.rb
+++ b/spec/features/staff/message_management_spec.rb
@@ -1,34 +1,66 @@
 require 'rails_helper'

-feature 'メッセージ管理機能' do
+feature 'スタッフによるメッセージ管理' do
   include FeaturesSpecHelper
   include PerformanceSpecHelper
   let(:staff_member) { create(:staff_member) }
-  let!(:root_message) { create(:customer_message, subject: 'Hello') }
-  let!(:reply1) { create(:staff_message, parent: root_message) }
-  let!(:message1) { create(:customer_message, parent: reply1) }
-  let!(:message2) { create(:customer_message, parent: reply1) }
-  let!(:reply2) { create(:staff_message, parent: message1) }
-  let!(:reply3) { create(:staff_message, parent: message1) }
-  let!(:message3) { create(:customer_message, parent: reply3) }
+  let(:customer) { create(:customer) }
+  let!(:root_message) { create(:customer_message, subject: 'Hello', customer: customer) }
+  let!(:reply1) { create(:staff_message, parent: root_message, staff_member: staff_member) }
+  let!(:message1) { create(:customer_message, parent: reply1, customer: customer) }
+  let!(:message2) { create(:customer_message, parent: reply1, customer: customer) }
+  let!(:reply2) { create(:staff_message, parent: message1, staff_member: staff_member) }
+  let!(:reply3) { create(:staff_message, parent: message1, staff_member: staff_member) }
+  let!(:message3) { create(:customer_message, parent: reply3, customer: customer) }

   before do
     switch_namespace(:staff)
     login_as_staff_member(staff_member)
   end

-  scenario 'メッセージツリーの表示', :performance do |example|
-    visit staff_message_path(message1)
+  scenario 'スタッフがメッセージ一覧を表示する' do
+    visit staff_messages_path
+    expect(page).to have_css('h1', text: I18n.t('staff.messages.index.title_index'))
+    expect(page).to have_content('Hello')
+  end
+
+  scenario 'スタッフが問い合わせ一覧を表示する' do
+    visit inbound_staff_messages_path
+    expect(page).to have_css('h1', text: I18n.t('staff.messages.index.title_inbound'))
+    expect(page).to have_content('Hello')
+  end
+
+  scenario 'スタッフが返信一覧を表示する' do
+    visit outbound_staff_messages_path
+    expect(page).to have_css('h1', text: I18n.t('staff.messages.index.title_outbound'))
+  end
+
+  scenario 'スタッフが顧客からのメッセージに返信する' do
+    visit staff_message_path(root_message)
+    within('.Table__links') do
+      click_link I18n.t('staff.messages.show.reply')
+    end
+
+    fill_in I18n.t('activerecord.attributes.message.subject'), with: 'Re: Hello'
+    fill_in I18n.t('activerecord.attributes.message.body'), with: 'This is a reply to your message.'
+    click_button I18n.t('staff.replies.new.confirm')
+    click_button I18n.t('staff.replies.confirm.send')
+
+    expect(page).to have_css('.Flash__notice', text: I18n.t('staff.replies.create.flash_notice'))
+    expect(StaffMessage.find_by(subject: 'Re: Hello', staff_member: staff_member)).to be_present
+  end
+
+  scenario 'スタッフが問い合わせを削除する' do
+    visit staff_message_path(root_message)
     expect(page).to have_css('h1', text: 'メッセージ詳細')
-    expect(page).to have_css('li a', text: 'Hello')

-    elapsed = Benchmark.realtime do
-      100.times do
-        visit staff_message_path(message1)
-      end
+    visit staff_messages_path
+
+    within("tr", text: root_message.subject) do
+      click_link I18n.t('staff.messages.index.delete')
     end

-    write_to_performance_log(example, elapsed)
-    expect(elapsed).to be < 100.0
+    expect(page).to have_css('.Flash__notice', text: I18n.t('staff.messages.destroy.flash_notice'))
+    expect(Message.find(root_message.id).deleted).to be true
   end
-end
\ No newline at end of file
+end

コミット: 6d58199

メッセージ

test(WIP):E2Eテスト

変更されたファイル

  • M app/controllers/staff/messages_controller.rb
  • M config/locales/controllers/ja.yml
  • M "docs/\343\203\246\343\203\274\343\202\271\343\202\261\343\203\274\343\202\271.md"
  • M spec/features/admin/staff_management_spec.rb
  • M spec/features/staff/customer_management_spec.rb

変更内容

commit 6d58199c85407137dc14704a0bec3563509c9758
Author: k2works <kakimomokuri@gmail.com>
Date:   Tue Jun 10 14:50:17 2025 +0900

    test(WIP):E2Eテスト

diff --git a/app/controllers/staff/messages_controller.rb b/app/controllers/staff/messages_controller.rb
index 00b5e99..815a060 100644
--- a/app/controllers/staff/messages_controller.rb
+++ b/app/controllers/staff/messages_controller.rb
@@ -45,7 +45,8 @@ class Staff::MessagesController < Staff::Base
     message = CustomerMessage.find(params[:id])
     message.update_column(:deleted, true)
     flash.notice = t('.flash_notice')
-    redirect_to :back
+
+    redirect_back(fallback_location: staff_message_path)
   end

   # POST/DELETE
diff --git a/config/locales/controllers/ja.yml b/config/locales/controllers/ja.yml
index 97ff6e3..4d16ae0 100644
--- a/config/locales/controllers/ja.yml
+++ b/config/locales/controllers/ja.yml
@@ -30,7 +30,7 @@ ja:
         flash_notice: '顧客を更新しました。'
         flash_alert: '入力に誤りがあります。'
       destroy:
-        flash_notice: '顧客をアカウントを削除しました。'
+        flash_notice: '顧客アカウントを削除しました。'
     programs:
       create:
         flash_notice: 'プログラムを登録しました。'
diff --git "a/docs/\343\203\246\343\203\274\343\202\271\343\202\261\343\203\274\343\202\271.md" "b/docs/\343\203\246\343\203\274\343\202\271\343\202\261\343\203\274\343\202\271.md"
index 41923d3..8d89046 100644
--- "a/docs/\343\203\246\343\203\274\343\202\271\343\202\261\343\203\274\343\202\271.md"
+++ "b/docs/\343\203\246\343\203\274\343\202\271\343\202\261\343\203\274\343\202\271.md"
@@ -218,7 +218,7 @@
 | 代替フロー | - キャンセル期限超過: キャンセルできない旨のメッセージを表示 |
 | 事後条件 | 予約がキャンセルされる |

-### 4.3. メッセージング
+### 4.3. 問い合わせ

 | ユースケースID | C-008 |
 | ------------- | ----- |
@@ -240,6 +240,17 @@
 | 代替フロー | - メッセージなし: メッセージがない旨のメッセージを表示 |
 | 事後条件 | メッセージ履歴が表示される |

+| ユースケースID | C-010                                             |
+| ------------- |---------------------------------------------------|
+| ユースケース名 | 問い合わせ返信                                           |
+| アクター | 顧客                                                |
+| 説明 | 顧客がスタッフのメッセージに返信する                                |
+| 事前条件 | 顧客がログイン済み、スタッフからメッセージが送信済み                        |
+| 基本フロー | 1. マイページのメッセージ履歴にアクセス<br>2. メッセージスレッドを選択<br>3. 返信 |
+| 代替フロー | - バリデーションエラー: エラーメッセージを表示し再編集を促す                  |
+| 事後条件 | 返信がスタッフに送信される                                     |
+
+
 ## 5. 管理者のユースケース

 ### 5.1. アカウント管理
diff --git a/spec/features/admin/staff_management_spec.rb b/spec/features/admin/staff_management_spec.rb
index a816337..d7c215e 100644
--- a/spec/features/admin/staff_management_spec.rb
+++ b/spec/features/admin/staff_management_spec.rb
@@ -61,4 +61,13 @@ feature '管理者によるスタッフ管理' do
     expect(page).to have_css('.Flash__notice', text: '職員アカウントを更新しました。')
     expect(staff_member.reload.suspended).to be_falsey
   end
+
+  scenario '管理者がスタッフアカウントを削除する' do
+    staff_member = create(:staff_member)
+    visit admin_staff_members_path
+
+    first('a', text: I18n.t('admin.staff_members.index.delete')).click
+
+    expect(page).to have_css('.Flash__notice', text: '職員アカウントを削除しました。')
+  end
 end
\ No newline at end of file
diff --git a/spec/features/staff/customer_management_spec.rb b/spec/features/staff/customer_management_spec.rb
index 2ce6bbe..9847cd7 100644
--- a/spec/features/staff/customer_management_spec.rb
+++ b/spec/features/staff/customer_management_spec.rb
@@ -118,4 +118,11 @@ feature '職員による顧客管理' do
     customer.reload
     expect(customer.work_address.company_name).to eq('テスト')
   end
+
+  scenario '職員が顧客を削除する' do
+    click_link I18n.t('staff.top.dashboard.staff_customers')
+    first('table.Table__body--listing').click_link I18n.t('staff.customers.index.delete')
+
+    expect(page).to have_css('.Flash__notice', text: '顧客アカウントを削除しました。')
+  end
 end

構造変更

uml diagram

コミット: ec454b9

メッセージ

test(WIP):E2Eテスト

変更されたファイル

  • M app/controllers/customer/messages_controller.rb
  • M app/models/message.rb
  • M "docs/\343\203\246\343\203\274\343\202\271\343\202\261\343\203\274\343\202\271.md"
  • M spec/factories/messages.rb
  • M spec/features/customer/message_management_spec.rb

変更内容

commit ec454b96d6c5f024cd58a0e33c0a461f376dd634
Author: k2works <kakimomokuri@gmail.com>
Date:   Tue Jun 10 14:13:42 2025 +0900

    test(WIP):E2Eテスト

diff --git a/app/controllers/customer/messages_controller.rb b/app/controllers/customer/messages_controller.rb
index 2877f1e..8c521f1 100644
--- a/app/controllers/customer/messages_controller.rb
+++ b/app/controllers/customer/messages_controller.rb
@@ -42,7 +42,8 @@ class Customer::MessagesController < Customer::Base
     message = StaffMessage.find(params[:id])
     message.update_column(:discarded, true)
     flash.notice = t('.flash_notice')
-    redirect_to :back
+
+    redirect_back(fallback_location: customer_root_path)
   end

   private
diff --git a/app/models/message.rb b/app/models/message.rb
index f9c8853..e54ddaa 100644
--- a/app/models/message.rb
+++ b/app/models/message.rb
@@ -31,7 +31,7 @@
 #

 class Message < ApplicationRecord
-  belongs_to :customer
+  belongs_to :customer, optional: true
   belongs_to :staff_member, optional: true
   belongs_to :root, class_name: 'Message', foreign_key: 'root_id', optional: true
   belongs_to :parent, class_name: 'Message', foreign_key: 'parent_id', optional: true
diff --git "a/docs/\343\203\246\343\203\274\343\202\271\343\202\261\343\203\274\343\202\271.md" "b/docs/\343\203\246\343\203\274\343\202\271\343\202\261\343\203\274\343\202\271.md"
index 2989e6a..41923d3 100644
--- "a/docs/\343\203\246\343\203\274\343\202\271\343\202\261\343\203\274\343\202\271.md"
+++ "b/docs/\343\203\246\343\203\274\343\202\271\343\202\261\343\203\274\343\202\271.md"
@@ -110,11 +110,11 @@
 | 代替フロー | - 参加者なし: 参加者がいない旨のメッセージを表示 |
 | 事後条件 | 参加者のステータスが更新される |

-### 3.4. メッセージング
+### 3.4. 問い合わせ

 | ユースケースID | S-010 |
 | ------------- | ----- |
-| ユースケース名 | 顧客へのメッセージ送信 |
+| ユースケース名 | 顧客への問い合わせ送信 |
 | アクター | スタッフ |
 | 説明 | スタッフが顧客にメッセージを送信する |
 | 事前条件 | スタッフがログイン済み、顧客が登録済み |
@@ -124,7 +124,7 @@

 | ユースケースID | S-011 |
 | ------------- | ----- |
-| ユースケース名 | 顧客からのメッセージ確認 |
+| ユースケース名 | 顧客からの問い合わせ確認 |
 | アクター | スタッフ |
 | 説明 | スタッフが顧客からのメッセージを確認する |
 | 事前条件 | スタッフがログイン済み、顧客からメッセージが送信済み |
@@ -134,7 +134,7 @@

 | ユースケースID | S-012 |
 | ------------- | ----- |
-| ユースケース名 | メッセージ返信 |
+| ユースケース名 | 問い合わせ返信 |
 | アクター | スタッフ |
 | 説明 | スタッフが顧客のメッセージに返信する |
 | 事前条件 | スタッフがログイン済み、顧客からメッセージが送信済み |
@@ -222,7 +222,7 @@

 | ユースケースID | C-008 |
 | ------------- | ----- |
-| ユースケース名 | スタッフへのメッセージ送信 |
+| ユースケース名 | スタッフへの問い合わせ送信 |
 | アクター | 顧客 |
 | 説明 | 顧客がスタッフにメッセージを送信する |
 | 事前条件 | 顧客がログイン済み |
@@ -232,7 +232,7 @@

 | ユースケースID | C-009 |
 | ------------- | ----- |
-| ユースケース名 | メッセージ履歴確認 |
+| ユースケース名 | 問い合わせ履歴確認 |
 | アクター | 顧客 |
 | 説明 | 顧客が過去のメッセージのやり取りを確認する |
 | 事前条件 | 顧客がログイン済み、メッセージのやり取りが存在する |
@@ -405,9 +405,9 @@ rectangle "スタッフのユースケース" {
   usecase "プログラム作成" as S007
   usecase "プログラム更新" as S008
   usecase "プログラム参加者管理" as S009
-  usecase "顧客へのメッセージ送信" as S010
-  usecase "顧客からのメッセージ確認" as S011
-  usecase "メッセージ返信" as S012
+  usecase "顧客への問い合わせ送信" as S010
+  usecase "顧客からの問い合わせ確認" as S011
+  usecase "問い合わせ返信" as S012
 }

 rectangle "顧客のユースケース" {
@@ -418,8 +418,8 @@ rectangle "顧客のユースケース" {
   usecase "プログラム閲覧" as C005
   usecase "プログラム予約" as C006
   usecase "予約キャンセル" as C007
-  usecase "スタッフへのメッセージ送信" as C008
-  usecase "メッセージ履歴確認" as C009
+  usecase "スタッフへの問い合わせ送信" as C008
+  usecase "問い合わせ履歴確認" as C009
 }

 rectangle "管理者のユースケース" {
diff --git a/spec/factories/messages.rb b/spec/factories/messages.rb
index f3b7548..20757bc 100644
--- a/spec/factories/messages.rb
+++ b/spec/factories/messages.rb
@@ -40,7 +40,7 @@ FactoryBot.define do
   factory :staff_message do
     subject {'Subject'}
     body {"Body.\nBody."}
-    parent { FactoryGirl.create(:customer_message)}
+    parent { FactoryBot.create(:customer_message)}
     staff_member
   end
 end
diff --git a/spec/features/customer/message_management_spec.rb b/spec/features/customer/message_management_spec.rb
index 91972d9..20f3550 100644
--- a/spec/features/customer/message_management_spec.rb
+++ b/spec/features/customer/message_management_spec.rb
@@ -11,59 +11,58 @@ feature '顧客によるメッセージ管理' do
   end

   scenario '顧客がスタッフにメッセージを送信する' do
-    visit customer_messages_path
-    click_link I18n.t('customer.messages.index.new')
-    
+    visit new_customer_message_path
+
     fill_in I18n.t('activerecord.attributes.message.subject'), with: 'テストメッセージ'
     fill_in I18n.t('activerecord.attributes.message.body'), with: 'これはテストメッセージです。'
-    select staff_member.family_name + staff_member.given_name, from: I18n.t('activerecord.attributes.message.staff_member_id')
     click_button I18n.t('customer.messages.new.submit')
+    click_button I18n.t('customer.messages.confirm.update')

-    expect(page).to have_css('.notice', text: I18n.t('customer.messages.create.notice'))
+    expect(page).to have_css('.Flash__notice', text: I18n.t('customer.messages.create.flash_notice'))
     expect(Message.find_by(subject: 'テストメッセージ', customer: customer)).to be_present
   end

   scenario '顧客がメッセージ履歴を確認する' do
     # Create a message from customer to staff
-    message = create(:message, customer: customer, staff_member: staff_member)
+    message = create(:customer_message, customer: customer)
     # Create a reply from staff to customer
-    create(:reply, message: message, staff_member: staff_member)
+    create(:staff_message, parent: message, staff_member: staff_member)

     visit customer_messages_path
-    click_link message.subject
-    
-    expect(page).to have_css('h1', text: message.subject)
-    expect(page).to have_content(message.body)
-    expect(page).to have_css('.replies .reply', count: 1)
+    click_link I18n.t('customer.messages.index.detail')
+
+    expect(page).to have_content(message.subject)
+    expect(page).to have_content(message.body.to_s.delete("\n"))
   end

-  scenario '顧客がメッセージを検索する' do
-    create(:message, customer: customer, staff_member: staff_member, subject: '問い合わせ')
-    create(:message, customer: customer, staff_member: staff_member, subject: '予約について')
-    
+  scenario '顧客がスタッフからのメッセージに回答する' do
+    # Create a message from customer to staff
+    message = create(:customer_message, customer: customer)
+    # Create a reply from staff to customer
+    create(:staff_message, parent: message, staff_member: staff_member)
+
     visit customer_messages_path
-    fill_in I18n.t('customer.messages.index.search_form.subject'), with: '予約'
-    click_button I18n.t('customer.messages.index.search_form.submit')
-    
-    expect(page).to have_content('予約について')
-    expect(page).not_to have_content('問い合わせ')
+    click_link I18n.t('customer.messages.index.detail')
+    click_link I18n.t('customer.messages.show.reply')
+    fill_in I18n.t('activerecord.attributes.message.subject'), with: '回答テストメッセージ'
+    fill_in I18n.t('activerecord.attributes.message.body'), with: 'これは回答テストメッセージです。'
+    click_button I18n.t('customer.replies.new.submit')
+    click_button I18n.t('customer.replies.confirm.send')
+
+    expect(page).to have_css('.Flash__notice', text: I18n.t('customer.replies.create.flash_notice'))
+    expect(Message.find_by(subject: '回答テストメッセージ', customer: customer)).to be_present
   end

-  scenario '顧客がメッセージにタグを付ける' do
-    tag = create(:tag, value: 'テストタグ')
-    
+  scenario '顧客がスタッフからのメッセージを削除する' do
+    # Create a message from customer to staff
+    message = create(:customer_message, customer: customer)
+    # Create a reply from staff to customer
+    create(:staff_message, parent: message, staff_member: staff_member)
+
     visit customer_messages_path
-    click_link I18n.t('customer.messages.index.new')
-    
-    fill_in I18n.t('activerecord.attributes.message.subject'), with: 'タグ付きメッセージ'
-    fill_in I18n.t('activerecord.attributes.message.body'), with: 'これはタグ付きメッセージです。'
-    select staff_member.family_name + staff_member.given_name, from: I18n.t('activerecord.attributes.message.staff_member_id')
-    check "tag_#{tag.id}"
-    click_button I18n.t('customer.messages.new.submit')
-    
-    expect(page).to have_css('.notice', text: I18n.t('customer.messages.create.notice'))
-    message = Message.find_by(subject: 'タグ付きメッセージ', customer: customer)
-    expect(message).to be_present
-    expect(message.tags).to include(tag)
+    click_link I18n.t('customer.messages.index.delete')
+
+    expect(page).to have_css('.Flash__notice', text: I18n.t('customer.messages.destroy.flash_notice'))
   end
+
 end
\ No newline at end of file

構造変更

uml diagram

コミット: 60822b7

メッセージ

test(WIP):E2Eテスト

変更されたファイル

  • M app/models/customer.rb

変更内容

commit 60822b76d4823db992bd35d8d0f18bc5eab9e35c
Author: k2works <kakimomokuri@gmail.com>
Date:   Mon Jun 9 19:04:54 2025 +0900

    test(WIP):E2Eテスト

diff --git a/app/models/customer.rb b/app/models/customer.rb
index d61ffce..03b7ec8 100644
--- a/app/models/customer.rb
+++ b/app/models/customer.rb
@@ -47,6 +47,11 @@ class Customer < ApplicationRecord
            -> { where(address_id: nil).order(:id) },
            class_name: 'Phone',
            autosave: true
+  has_many :entries, dependent: :destroy
+  has_many :programs, through: :entries
+  has_many :messages
+  has_many :outbound_messages, class_name: 'CustomerMessage', foreign_key: 'customer_id'
+  has_many :inbound_messages, class_name: 'StaffMessage', foreign_key: 'customer_id'

   validates :gender, inclusion: { in: %w(male female), allow_blank: true }
   validates :birthday, date: {

構造変更

uml diagram

コミット: 01e2dca

メッセージ

test(WIP):E2Eテスト

変更されたファイル

  • M "docs/\343\203\246\343\203\274\343\202\271\343\202\261\343\203\274\343\202\271.md"
  • M spec/features/admin/account_management_spec.rb
  • M spec/features/admin/staff_management_spec.rb
  • M spec/features/admin/system_management_spec.rb

変更内容

commit 01e2dca118613fd499eac83d7a10924d02e778d3
Author: k2works <kakimomokuri@gmail.com>
Date:   Mon Jun 9 18:40:01 2025 +0900

    test(WIP):E2Eテスト

diff --git "a/docs/\343\203\246\343\203\274\343\202\271\343\202\261\343\203\274\343\202\271.md" "b/docs/\343\203\246\343\203\274\343\202\271\343\202\261\343\203\274\343\202\271.md"
index aeee4d3..2989e6a 100644
--- "a/docs/\343\203\246\343\203\274\343\202\271\343\202\261\343\203\274\343\202\271.md"
+++ "b/docs/\343\203\246\343\203\274\343\202\271\343\202\261\343\203\274\343\202\271.md"
@@ -328,16 +328,6 @@
 | 代替フロー | - バリデーションエラー: エラーメッセージを表示し再編集を促す |
 | 事後条件 | アクセス制限設定が更新される |

-| ユースケースID | A-009 |
-| ------------- | ----- |
-| ユースケース名 | タグ管理 |
-| アクター | 管理者 |
-| 説明 | 管理者がメッセージングで使用するタグを管理する |
-| 事前条件 | 管理者がログイン済み |
-| 基本フロー | 1. タグ管理ページにアクセス<br>2. タグを追加/編集/削除<br>3. 変更を保存 |
-| 代替フロー | - バリデーションエラー: エラーメッセージを表示し再編集を促す |
-| 事後条件 | タグ設定が更新される |
-
 ## 6. システム間ユースケース

 | ユースケースID | SYS-001 |
diff --git a/spec/features/admin/account_management_spec.rb b/spec/features/admin/account_management_spec.rb
index 6d43ea4..919a2c1 100644
--- a/spec/features/admin/account_management_spec.rb
+++ b/spec/features/admin/account_management_spec.rb
@@ -17,15 +17,15 @@ feature '管理者によるアカウント管理' do
     end

     expect(current_path).to eq(admin_root_path)
-    expect(page).to have_content(administrator.email)
+    expect(page).to have_content("ログインしました")
   end

   scenario '管理者がログアウトする' do
     login_as_administrator(administrator)
     click_link I18n.t('admin.shared.header.logout')

-    expect(current_path).to eq(admin_login_path)
-    expect(page).to have_css('.notice', text: I18n.t('admin.sessions.destroy.notice'))
+    expect(current_path).to eq(admin_root_path)
+    expect(page).to have_content("ログアウトしました")
   end

   scenario '管理者が無効なパスワードでログインを試みる' do
@@ -36,7 +36,6 @@ feature '管理者によるアカウント管理' do
       click_button I18n.t('admin.sessions.new.submit')
     end

-    expect(current_path).to eq(admin_login_path)
-    expect(page).to have_css('.alert', text: I18n.t('admin.sessions.create.alert'))
+    expect(current_path).to eq(admin_session_path)
   end
 end
\ No newline at end of file
diff --git a/spec/features/admin/staff_management_spec.rb b/spec/features/admin/staff_management_spec.rb
index ff3e2aa..a816337 100644
--- a/spec/features/admin/staff_management_spec.rb
+++ b/spec/features/admin/staff_management_spec.rb
@@ -10,54 +10,55 @@ feature '管理者によるスタッフ管理' do
   end

   scenario '管理者が新規スタッフアカウントを作成する' do
-    click_link I18n.t('admin.staff_members.index.new')
+    click_link I18n.t('admin.top.dashboard.admin_staff_members')
+    first('a', text: I18n.t('admin.staff_members.index.new')).click

     fill_in I18n.t('activerecord.attributes.staff_member.email'), with: 'test@example.com'
     fill_in I18n.t('activerecord.attributes.staff_member.family_name'), with: '試験'
     fill_in I18n.t('activerecord.attributes.staff_member.given_name'), with: '太郎'
     fill_in I18n.t('activerecord.attributes.staff_member.family_name_kana'), with: 'シケン'
     fill_in I18n.t('activerecord.attributes.staff_member.given_name_kana'), with: 'タロウ'
-    fill_in I18n.t('activerecord.attributes.staff_member.password'), with: 'password'
-    click_button I18n.t('admin.staff_members.new.submit')
+    fill_in I18n.t('activerecord.attributes.staff_member.hashed_password'), with: 'password'
+    fill_in I18n.t('activerecord.attributes.staff_member.start_date'), with: Date.today.strftime('%Y-%m-%d')
+    click_button I18n.t('admin.staff_members.new.create')

-    expect(page).to have_css('.notice', text: I18n.t('admin.staff_members.create.notice'))
+    expect(page).to have_css('.Flash__notice', text: '職員アカウントを新規登録しました。')
     expect(StaffMember.find_by(email: 'test@example.com')).to be_present
   end

   scenario '管理者がスタッフアカウントを編集する' do
     staff_member = create(:staff_member)
     visit admin_staff_members_path
-    click_link staff_member.family_name + staff_member.given_name

-    click_link I18n.t('admin.staff_members.show.edit')
+    first('a', text: I18n.t('admin.staff_members.index.edit')).click
     fill_in I18n.t('activerecord.attributes.staff_member.email'), with: 'edited@example.com'
-    click_button I18n.t('admin.staff_members.edit.submit')
+    click_button I18n.t('admin.staff_members.edit.update')

-    expect(page).to have_css('.notice', text: I18n.t('admin.staff_members.update.notice'))
+    expect(page).to have_css('.Flash__notice', text: '職員アカウントを更新しました。')
     expect(staff_member.reload.email).to eq('edited@example.com')
   end

   scenario '管理者がスタッフアカウントを停止する' do
     staff_member = create(:staff_member)
     visit admin_staff_members_path
-    
-    within("#staff_member_#{staff_member.id}") do
-      click_link I18n.t('admin.staff_members.index.suspend')
-    end

-    expect(page).to have_css('.notice', text: I18n.t('admin.staff_members.suspend.notice'))
+    first('a', text: I18n.t('admin.staff_members.index.edit')).click
+    check I18n.t('activerecord.attributes.staff_member.suspended')
+    click_button I18n.t('admin.staff_members.edit.update')
+
+    expect(page).to have_css('.Flash__notice', text: '職員アカウントを更新しました。')
     expect(staff_member.reload.suspended).to be_truthy
   end

   scenario '管理者がスタッフアカウントを再開する' do
     staff_member = create(:staff_member, suspended: true)
     visit admin_staff_members_path
-    
-    within("#staff_member_#{staff_member.id}") do
-      click_link I18n.t('admin.staff_members.index.resume')
-    end

-    expect(page).to have_css('.notice', text: I18n.t('admin.staff_members.resume.notice'))
+    first('a', text: I18n.t('admin.staff_members.index.edit')).click
+    uncheck I18n.t('activerecord.attributes.staff_member.suspended')
+    click_button I18n.t('admin.staff_members.edit.update')
+
+    expect(page).to have_css('.Flash__notice', text: '職員アカウントを更新しました。')
     expect(staff_member.reload.suspended).to be_falsey
   end
 end
\ No newline at end of file
diff --git a/spec/features/admin/system_management_spec.rb b/spec/features/admin/system_management_spec.rb
index 88c77fd..ca56786 100644
--- a/spec/features/admin/system_management_spec.rb
+++ b/spec/features/admin/system_management_spec.rb
@@ -15,51 +15,22 @@ feature '管理者によるシステム管理' do
     staff_member.events.create!(type: 'logged_in')
     staff_member.events.create!(type: 'logged_out')

-    visit admin_staff_member_path(staff_member)
-    click_link I18n.t('admin.staff_members.show.events')
-    
+    visit admin_staff_events_path
+
     expect(page).to have_css('h1', text: I18n.t('admin.staff_events.index.title'))
-    expect(page).to have_selector('table.staff-events tbody tr', count: 2)
+    expect(page).to have_selector('table.Table__body tr.Table__tr', count: 3)
   end

   scenario '管理者がIPアドレス制限を設定する' do
     visit admin_allowed_sources_path
-    click_link I18n.t('admin.allowed_sources.index.new')
-    
-    fill_in I18n.t('activerecord.attributes.allowed_source.octet1'), with: '192'
-    fill_in I18n.t('activerecord.attributes.allowed_source.octet2'), with: '168'
-    fill_in I18n.t('activerecord.attributes.allowed_source.octet3'), with: '1'
-    fill_in I18n.t('activerecord.attributes.allowed_source.octet4'), with: '0'
-    fill_in I18n.t('activerecord.attributes.allowed_source.wildcard'), with: true
-    fill_in I18n.t('activerecord.attributes.allowed_source.note'), with: 'テスト用'
-    click_button I18n.t('admin.allowed_sources.new.submit')
-    
-    expect(page).to have_css('.notice', text: I18n.t('admin.allowed_sources.create.notice'))
-    expect(AllowedSource.find_by(octet1: 192, octet2: 168, octet3: 1, octet4: 0, wildcard: true)).to be_present
-  end

-  scenario '管理者がタグを管理する' do
-    visit admin_tags_path
-    click_link I18n.t('admin.tags.index.new')
-    
-    fill_in I18n.t('activerecord.attributes.tag.value'), with: 'テストタグ'
-    click_button I18n.t('admin.tags.new.submit')
-    
-    expect(page).to have_css('.notice', text: I18n.t('admin.tags.create.notice'))
-    expect(Tag.find_by(value: 'テストタグ')).to be_present
-    
-    # Edit tag
-    click_link 'テストタグ'
-    click_link I18n.t('admin.tags.show.edit')
-    fill_in I18n.t('activerecord.attributes.tag.value'), with: '更新タグ'
-    click_button I18n.t('admin.tags.edit.submit')
-    
-    expect(page).to have_css('.notice', text: I18n.t('admin.tags.update.notice'))
-    expect(Tag.find_by(value: '更新タグ')).to be_present
-    
-    # Delete tag
-    click_link I18n.t('admin.tags.show.delete')
-    expect(page).to have_css('.notice', text: I18n.t('admin.tags.destroy.notice'))
-    expect(Tag.find_by(value: '更新タグ')).to be_nil
+    fill_in 'allowed_source_octet1', with: '192'
+    fill_in 'allowed_source_octet2', with: '168'
+    fill_in 'allowed_source_octet3', with: '1'
+    fill_in 'allowed_source_last_octet', with: '*'
+    click_button '追加'
+
+    expect(page).to have_css('.Flash__notice', text: I18n.t('admin.allowed_sources.create.flash_notice'))
+    expect(AllowedSource.find_by(octet1: 192, octet2: 168, octet3: 1, octet4: 0, wildcard: true)).to be_present
   end
 end
\ No newline at end of file

コミット: fc160e1

メッセージ

chore:スクリーンショット設定

変更されたファイル

  • M spec/rails_helper.rb

変更内容

commit fc160e11784d9a3980544b9f11f4f17635d651f8
Author: k2works <kakimomokuri@gmail.com>
Date:   Mon Jun 9 18:39:20 2025 +0900

    chore:スクリーンショット設定

diff --git a/spec/rails_helper.rb b/spec/rails_helper.rb
index bd111bc..cd000d0 100644
--- a/spec/rails_helper.rb
+++ b/spec/rails_helper.rb
@@ -11,6 +11,7 @@ require 'rspec/rails'
 require 'capybara/rails'
 require 'capybara/rspec'
 require 'selenium-webdriver'
+require 'capybara-screenshot/rspec'

 # Chrome Headless設定
 Capybara.register_driver :selenium_chrome_headless do |app|
@@ -49,6 +50,10 @@ Capybara.default_max_wait_time = 5
 Capybara.server_host = '0.0.0.0'
 Capybara.server_port = 3001

+# スクリーンショット設定
+Capybara::Screenshot.autosave_on_failure = true
+Capybara::Screenshot.prune_strategy = :keep_last_run
+
 # Requires supporting ruby files with custom matchers and macros, etc, in
 # spec/support/ and its subdirectories. Files matching `spec/**/*_spec.rb` are
 # run as spec files by default. This means that files in spec/support that end

コミット: 3e43b03

メッセージ

fix:シード

変更されたファイル

  • M app/models/message.rb
  • A spec/models/customer_message_spec.rb
  • A test_customer_message.rb

変更内容

commit 3e43b0320d45a3e08b3ede2b65c816f0d15b5625
Author: k2works <kakimomokuri@gmail.com>
Date:   Mon Jun 9 16:47:32 2025 +0900

    fix:シード

diff --git a/app/models/message.rb b/app/models/message.rb
index 3364e95..f9c8853 100644
--- a/app/models/message.rb
+++ b/app/models/message.rb
@@ -32,9 +32,9 @@

 class Message < ApplicationRecord
   belongs_to :customer
-  belongs_to :staff_member
-  belongs_to :root, class_name: 'Message', foreign_key: 'root_id'
-  belongs_to :parent, class_name: 'Message', foreign_key: 'parent_id'
+  belongs_to :staff_member, optional: true
+  belongs_to :root, class_name: 'Message', foreign_key: 'root_id', optional: true
+  belongs_to :parent, class_name: 'Message', foreign_key: 'parent_id', optional: true
   has_many :message_tag_links, dependent: :destroy
   has_many :tags, -> { order(:value)}, through: :message_tag_links

diff --git a/spec/models/customer_message_spec.rb b/spec/models/customer_message_spec.rb
new file mode 100644
index 0000000..a51f646
--- /dev/null
+++ b/spec/models/customer_message_spec.rb
@@ -0,0 +1,17 @@
+require 'rails_helper'
+
+RSpec.describe CustomerMessage, type: :model do
+  describe 'validations' do
+    it 'can be created without staff_member, root, or parent' do
+      customer = FactoryBot.create(:customer)
+      message = CustomerMessage.new(
+        customer: customer,
+        subject: 'Test Subject',
+        body: 'Test Body'
+      )
+      
+      expect(message).to be_valid
+      expect { message.save! }.not_to raise_error
+    end
+  end
+end
\ No newline at end of file
diff --git a/test_customer_message.rb b/test_customer_message.rb
new file mode 100644
index 0000000..f754441
--- /dev/null
+++ b/test_customer_message.rb
@@ -0,0 +1,29 @@
+#!/usr/bin/env ruby
+require_relative 'config/environment'
+
+# Create a customer
+customer = Customer.first || Customer.create!(
+  email: 'test@example.com',
+  family_name: 'Test',
+  given_name: 'User',
+  family_name_kana: 'テスト',
+  given_name_kana: 'ユーザー',
+  password: 'password',
+  birthday: Date.new(1980, 1, 1),
+  gender: 'male'
+)
+
+# Create a CustomerMessage without staff_member, root, or parent
+message = CustomerMessage.new(
+  customer: customer,
+  subject: 'Test Subject',
+  body: 'Test Body'
+)
+
+puts "Message valid? #{message.valid?}"
+if message.valid?
+  message.save!
+  puts "Message saved successfully with ID: #{message.id}"
+else
+  puts "Message validation errors: #{message.errors.full_messages.join(', ')}"
+end
\ No newline at end of file

構造変更

uml diagram

コミット: 6e9569a

メッセージ

test(WIP):E2Eテスト

変更されたファイル

  • A spec/features/admin/account_management_spec.rb
  • A spec/features/admin/staff_management_spec.rb
  • A spec/features/admin/system_management_spec.rb
  • A spec/features/customer/message_management_spec.rb
  • A spec/features/customer/program_management_spec.rb
  • M spec/support/features_spec_helper.rb

変更内容

commit 6e9569aed1d38e5f97f2b43ec56b2cb6155ab99c
Author: k2works <kakimomokuri@gmail.com>
Date:   Mon Jun 9 16:22:15 2025 +0900

    test(WIP):E2Eテスト

diff --git a/spec/features/admin/account_management_spec.rb b/spec/features/admin/account_management_spec.rb
new file mode 100644
index 0000000..6d43ea4
--- /dev/null
+++ b/spec/features/admin/account_management_spec.rb
@@ -0,0 +1,42 @@
+require 'rails_helper'
+
+feature '管理者によるアカウント管理' do
+  include FeaturesSpecHelper
+  let(:administrator) { create(:administrator) }
+
+  before do
+    switch_namespace(:admin)
+  end
+
+  scenario '管理者がログインする' do
+    visit admin_login_path
+    within('.Login--admin') do
+      fill_in I18n.t('activemodel.attributes.admin/login_form.email'), with: administrator.email
+      fill_in I18n.t('activemodel.attributes.admin/login_form.password'), with: 'pw'
+      click_button I18n.t('admin.sessions.new.submit')
+    end
+
+    expect(current_path).to eq(admin_root_path)
+    expect(page).to have_content(administrator.email)
+  end
+
+  scenario '管理者がログアウトする' do
+    login_as_administrator(administrator)
+    click_link I18n.t('admin.shared.header.logout')
+    
+    expect(current_path).to eq(admin_login_path)
+    expect(page).to have_css('.notice', text: I18n.t('admin.sessions.destroy.notice'))
+  end
+
+  scenario '管理者が無効なパスワードでログインを試みる' do
+    visit admin_login_path
+    within('.Login--admin') do
+      fill_in I18n.t('activemodel.attributes.admin/login_form.email'), with: administrator.email
+      fill_in I18n.t('activemodel.attributes.admin/login_form.password'), with: 'wrong_password'
+      click_button I18n.t('admin.sessions.new.submit')
+    end
+
+    expect(current_path).to eq(admin_login_path)
+    expect(page).to have_css('.alert', text: I18n.t('admin.sessions.create.alert'))
+  end
+end
\ No newline at end of file
diff --git a/spec/features/admin/staff_management_spec.rb b/spec/features/admin/staff_management_spec.rb
new file mode 100644
index 0000000..ff3e2aa
--- /dev/null
+++ b/spec/features/admin/staff_management_spec.rb
@@ -0,0 +1,63 @@
+require 'rails_helper'
+
+feature '管理者によるスタッフ管理' do
+  include FeaturesSpecHelper
+  let(:administrator) { create(:administrator) }
+
+  before do
+    switch_namespace(:admin)
+    login_as_administrator(administrator)
+  end
+
+  scenario '管理者が新規スタッフアカウントを作成する' do
+    click_link I18n.t('admin.staff_members.index.new')
+    
+    fill_in I18n.t('activerecord.attributes.staff_member.email'), with: 'test@example.com'
+    fill_in I18n.t('activerecord.attributes.staff_member.family_name'), with: '試験'
+    fill_in I18n.t('activerecord.attributes.staff_member.given_name'), with: '太郎'
+    fill_in I18n.t('activerecord.attributes.staff_member.family_name_kana'), with: 'シケン'
+    fill_in I18n.t('activerecord.attributes.staff_member.given_name_kana'), with: 'タロウ'
+    fill_in I18n.t('activerecord.attributes.staff_member.password'), with: 'password'
+    click_button I18n.t('admin.staff_members.new.submit')
+
+    expect(page).to have_css('.notice', text: I18n.t('admin.staff_members.create.notice'))
+    expect(StaffMember.find_by(email: 'test@example.com')).to be_present
+  end
+
+  scenario '管理者がスタッフアカウントを編集する' do
+    staff_member = create(:staff_member)
+    visit admin_staff_members_path
+    click_link staff_member.family_name + staff_member.given_name
+
+    click_link I18n.t('admin.staff_members.show.edit')
+    fill_in I18n.t('activerecord.attributes.staff_member.email'), with: 'edited@example.com'
+    click_button I18n.t('admin.staff_members.edit.submit')
+
+    expect(page).to have_css('.notice', text: I18n.t('admin.staff_members.update.notice'))
+    expect(staff_member.reload.email).to eq('edited@example.com')
+  end
+
+  scenario '管理者がスタッフアカウントを停止する' do
+    staff_member = create(:staff_member)
+    visit admin_staff_members_path
+    
+    within("#staff_member_#{staff_member.id}") do
+      click_link I18n.t('admin.staff_members.index.suspend')
+    end
+
+    expect(page).to have_css('.notice', text: I18n.t('admin.staff_members.suspend.notice'))
+    expect(staff_member.reload.suspended).to be_truthy
+  end
+
+  scenario '管理者がスタッフアカウントを再開する' do
+    staff_member = create(:staff_member, suspended: true)
+    visit admin_staff_members_path
+    
+    within("#staff_member_#{staff_member.id}") do
+      click_link I18n.t('admin.staff_members.index.resume')
+    end
+
+    expect(page).to have_css('.notice', text: I18n.t('admin.staff_members.resume.notice'))
+    expect(staff_member.reload.suspended).to be_falsey
+  end
+end
\ No newline at end of file
diff --git a/spec/features/admin/system_management_spec.rb b/spec/features/admin/system_management_spec.rb
new file mode 100644
index 0000000..88c77fd
--- /dev/null
+++ b/spec/features/admin/system_management_spec.rb
@@ -0,0 +1,65 @@
+require 'rails_helper'
+
+feature '管理者によるシステム管理' do
+  include FeaturesSpecHelper
+  let(:administrator) { create(:administrator) }
+
+  before do
+    switch_namespace(:admin)
+    login_as_administrator(administrator)
+  end
+
+  scenario '管理者がスタッフイベントログを確認する' do
+    staff_member = create(:staff_member)
+    # Create some staff events
+    staff_member.events.create!(type: 'logged_in')
+    staff_member.events.create!(type: 'logged_out')
+    
+    visit admin_staff_member_path(staff_member)
+    click_link I18n.t('admin.staff_members.show.events')
+    
+    expect(page).to have_css('h1', text: I18n.t('admin.staff_events.index.title'))
+    expect(page).to have_selector('table.staff-events tbody tr', count: 2)
+  end
+
+  scenario '管理者がIPアドレス制限を設定する' do
+    visit admin_allowed_sources_path
+    click_link I18n.t('admin.allowed_sources.index.new')
+    
+    fill_in I18n.t('activerecord.attributes.allowed_source.octet1'), with: '192'
+    fill_in I18n.t('activerecord.attributes.allowed_source.octet2'), with: '168'
+    fill_in I18n.t('activerecord.attributes.allowed_source.octet3'), with: '1'
+    fill_in I18n.t('activerecord.attributes.allowed_source.octet4'), with: '0'
+    fill_in I18n.t('activerecord.attributes.allowed_source.wildcard'), with: true
+    fill_in I18n.t('activerecord.attributes.allowed_source.note'), with: 'テスト用'
+    click_button I18n.t('admin.allowed_sources.new.submit')
+    
+    expect(page).to have_css('.notice', text: I18n.t('admin.allowed_sources.create.notice'))
+    expect(AllowedSource.find_by(octet1: 192, octet2: 168, octet3: 1, octet4: 0, wildcard: true)).to be_present
+  end
+
+  scenario '管理者がタグを管理する' do
+    visit admin_tags_path
+    click_link I18n.t('admin.tags.index.new')
+    
+    fill_in I18n.t('activerecord.attributes.tag.value'), with: 'テストタグ'
+    click_button I18n.t('admin.tags.new.submit')
+    
+    expect(page).to have_css('.notice', text: I18n.t('admin.tags.create.notice'))
+    expect(Tag.find_by(value: 'テストタグ')).to be_present
+    
+    # Edit tag
+    click_link 'テストタグ'
+    click_link I18n.t('admin.tags.show.edit')
+    fill_in I18n.t('activerecord.attributes.tag.value'), with: '更新タグ'
+    click_button I18n.t('admin.tags.edit.submit')
+    
+    expect(page).to have_css('.notice', text: I18n.t('admin.tags.update.notice'))
+    expect(Tag.find_by(value: '更新タグ')).to be_present
+    
+    # Delete tag
+    click_link I18n.t('admin.tags.show.delete')
+    expect(page).to have_css('.notice', text: I18n.t('admin.tags.destroy.notice'))
+    expect(Tag.find_by(value: '更新タグ')).to be_nil
+  end
+end
\ No newline at end of file
diff --git a/spec/features/customer/message_management_spec.rb b/spec/features/customer/message_management_spec.rb
new file mode 100644
index 0000000..91972d9
--- /dev/null
+++ b/spec/features/customer/message_management_spec.rb
@@ -0,0 +1,69 @@
+require 'rails_helper'
+
+feature '顧客によるメッセージ管理' do
+  include FeaturesSpecHelper
+  let(:customer) { create(:customer) }
+  let(:staff_member) { create(:staff_member) }
+
+  before do
+    switch_namespace(:customer)
+    login_as_customer(customer)
+  end
+
+  scenario '顧客がスタッフにメッセージを送信する' do
+    visit customer_messages_path
+    click_link I18n.t('customer.messages.index.new')
+    
+    fill_in I18n.t('activerecord.attributes.message.subject'), with: 'テストメッセージ'
+    fill_in I18n.t('activerecord.attributes.message.body'), with: 'これはテストメッセージです。'
+    select staff_member.family_name + staff_member.given_name, from: I18n.t('activerecord.attributes.message.staff_member_id')
+    click_button I18n.t('customer.messages.new.submit')
+    
+    expect(page).to have_css('.notice', text: I18n.t('customer.messages.create.notice'))
+    expect(Message.find_by(subject: 'テストメッセージ', customer: customer)).to be_present
+  end
+
+  scenario '顧客がメッセージ履歴を確認する' do
+    # Create a message from customer to staff
+    message = create(:message, customer: customer, staff_member: staff_member)
+    # Create a reply from staff to customer
+    create(:reply, message: message, staff_member: staff_member)
+    
+    visit customer_messages_path
+    click_link message.subject
+    
+    expect(page).to have_css('h1', text: message.subject)
+    expect(page).to have_content(message.body)
+    expect(page).to have_css('.replies .reply', count: 1)
+  end
+
+  scenario '顧客がメッセージを検索する' do
+    create(:message, customer: customer, staff_member: staff_member, subject: '問い合わせ')
+    create(:message, customer: customer, staff_member: staff_member, subject: '予約について')
+    
+    visit customer_messages_path
+    fill_in I18n.t('customer.messages.index.search_form.subject'), with: '予約'
+    click_button I18n.t('customer.messages.index.search_form.submit')
+    
+    expect(page).to have_content('予約について')
+    expect(page).not_to have_content('問い合わせ')
+  end
+
+  scenario '顧客がメッセージにタグを付ける' do
+    tag = create(:tag, value: 'テストタグ')
+    
+    visit customer_messages_path
+    click_link I18n.t('customer.messages.index.new')
+    
+    fill_in I18n.t('activerecord.attributes.message.subject'), with: 'タグ付きメッセージ'
+    fill_in I18n.t('activerecord.attributes.message.body'), with: 'これはタグ付きメッセージです。'
+    select staff_member.family_name + staff_member.given_name, from: I18n.t('activerecord.attributes.message.staff_member_id')
+    check "tag_#{tag.id}"
+    click_button I18n.t('customer.messages.new.submit')
+    
+    expect(page).to have_css('.notice', text: I18n.t('customer.messages.create.notice'))
+    message = Message.find_by(subject: 'タグ付きメッセージ', customer: customer)
+    expect(message).to be_present
+    expect(message.tags).to include(tag)
+  end
+end
\ No newline at end of file
diff --git a/spec/features/customer/program_management_spec.rb b/spec/features/customer/program_management_spec.rb
new file mode 100644
index 0000000..8341e2d
--- /dev/null
+++ b/spec/features/customer/program_management_spec.rb
@@ -0,0 +1,68 @@
+require 'rails_helper'
+
+feature '顧客によるプログラム管理' do
+  include FeaturesSpecHelper
+  let(:customer) { create(:customer) }
+  let!(:program) { create(:program, application_start_time: 2.days.ago, application_end_time: 2.days.from_now) }
+
+  before do
+    switch_namespace(:customer)
+    login_as_customer(customer)
+  end
+
+  scenario '顧客がプログラム一覧を閲覧する' do
+    visit customer_programs_path
+    
+    expect(page).to have_css('h1', text: I18n.t('customer.programs.index.title'))
+    expect(page).to have_content(program.title)
+  end
+
+  scenario '顧客がプログラム詳細を閲覧する' do
+    visit customer_programs_path
+    click_link program.title
+    
+    expect(page).to have_css('h1', text: program.title)
+    expect(page).to have_content(program.description)
+  end
+
+  scenario '顧客がプログラムを予約する' do
+    visit customer_program_path(program)
+    click_link I18n.t('customer.programs.show.apply')
+    
+    fill_in I18n.t('activerecord.attributes.entry.remarks'), with: 'テスト予約'
+    click_button I18n.t('customer.entries.new.submit')
+    
+    expect(page).to have_css('.notice', text: I18n.t('customer.entries.create.notice'))
+    expect(Entry.find_by(program: program, customer: customer)).to be_present
+  end
+
+  scenario '顧客が予約をキャンセルする' do
+    entry = create(:entry, program: program, customer: customer)
+    
+    visit customer_entries_path
+    click_link program.title
+    click_link I18n.t('customer.entries.show.cancel')
+    
+    expect(page).to have_css('.notice', text: I18n.t('customer.entries.cancel.notice'))
+    expect(entry.reload.canceled).to be_truthy
+  end
+
+  scenario '顧客が予約期間外のプログラムを予約しようとする' do
+    closed_program = create(:program, application_start_time: 10.days.from_now, application_end_time: 20.days.from_now)
+    
+    visit customer_program_path(closed_program)
+    
+    expect(page).not_to have_link(I18n.t('customer.programs.show.apply'))
+    expect(page).to have_content(I18n.t('customer.programs.show.not_applicable'))
+  end
+
+  scenario '顧客が定員超過のプログラムを予約しようとする' do
+    full_program = create(:program, application_start_time: 2.days.ago, application_end_time: 2.days.from_now, max_number_of_participants: 1)
+    create(:entry, program: full_program) # Fill the program
+    
+    visit customer_program_path(full_program)
+    
+    expect(page).not_to have_link(I18n.t('customer.programs.show.apply'))
+    expect(page).to have_content(I18n.t('customer.programs.show.full'))
+  end
+end
\ No newline at end of file
diff --git a/spec/support/features_spec_helper.rb b/spec/support/features_spec_helper.rb
index c17fb25..aac0165 100644
--- a/spec/support/features_spec_helper.rb
+++ b/spec/support/features_spec_helper.rb
@@ -21,4 +21,13 @@ module FeaturesSpecHelper
       click_button I18n.t('customer.sessions.new.submit')
     end
   end
-end
\ No newline at end of file
+
+  def login_as_administrator(administrator, password = 'pw')
+    visit admin_login_path
+    within('.Login--admin') do
+      fill_in I18n.t('activemodel.attributes.admin/login_form.email'), with: administrator.email
+      fill_in I18n.t('activemodel.attributes.admin/login_form.password'), with: password
+      click_button I18n.t('admin.sessions.new.submit')
+    end
+  end
+end

コミット: b0dca43

メッセージ

test:E2Eテスト

変更されたファイル

  • M spec/features/staff/customer_management_spec.rb
  • M spec/features/staff/phone_management_spec.rb
  • M spec/features/staff/program_management_spec.rb

変更内容

commit b0dca43861f203f72561b12aeb36f99963f5b171
Author: k2works <kakimomokuri@gmail.com>
Date:   Mon Jun 9 16:09:12 2025 +0900

    test:E2Eテスト

diff --git a/spec/features/staff/customer_management_spec.rb b/spec/features/staff/customer_management_spec.rb
index 8aac7ee..2ce6bbe 100644
--- a/spec/features/staff/customer_management_spec.rb
+++ b/spec/features/staff/customer_management_spec.rb
@@ -1,7 +1,6 @@
 require 'rails_helper'

-# 職員による顧客管理
-feature 'Customer management by staff' do
+feature '職員による顧客管理' do
   include FeaturesSpecHelper
   let(:staff_member) { create(:staff_member) }
   let!(:customer) { create(:customer) }
@@ -11,8 +10,7 @@ feature 'Customer management by staff' do
     login_as_staff_member(staff_member)
   end

-  # 職員が顧客(基本情報のみ)を登録する
-  scenario 'Employees register customers (only basic information)' do
+  scenario '職員が顧客(基本情報のみ)を登録する' do
     click_link I18n.t('staff.top.dashboard.staff_customers')
     first('.Table__links').click_link I18n.t('staff.customers.index.new')
     fill_in I18n.t('activerecord.attributes.customer.email'), with: 'test@example.jp'
@@ -33,8 +31,7 @@ feature 'Customer management by staff' do
     expect(new_customer.work_address).to be_nil
   end

-  # 職員が顧客、自宅住所、勤務先を更新する
-  scenario 'Staff update customer, home address, work place' do
+  scenario '職員が顧客、自宅住所、勤務先を更新する' do
     click_link I18n.t('staff.top.dashboard.staff_customers')
     first('table.Table__body--listing').click_link I18n.t('staff.customers.index.edit')

@@ -53,8 +50,7 @@ feature 'Customer management by staff' do
     expect(customer.work_address.company_name).to eq('テスト')
   end

-  # 職員が顧客、自宅住所、勤務先を登録する
-  scenario 'Employees register customer, home address, work place' do
+  scenario '職員が顧客、自宅住所、勤務先を登録する' do
     click_link I18n.t('staff.top.dashboard.staff_customers')
     first('.Table__links').click_link I18n.t('staff.customers.index.new')

@@ -94,8 +90,7 @@ feature 'Customer management by staff' do
     expect(new_customer.work_address.company_name).to eq('テスト')
   end

-  # 職員が生年月日と自宅の郵便番号に無効な値を入力する
-  scenario 'Employees enter invalid values for birth date and home postal code' do
+  scenario '職員が生年月日と自宅の郵便番号に無効な値を入力する' do
     click_link I18n.t('staff.top.dashboard.staff_customers')
     first('table.Table__body--listing').click_link I18n.t('staff.customers.index.edit')

@@ -109,8 +104,7 @@ feature 'Customer management by staff' do
     expect(page).to have_css('.has-error span.help-block')
   end

-  # 職員が勤務先データのない既存顧客に会社名の情報を追加する
-  scenario 'Staff add company name information to existing customers that do not have work data' do
+  scenario '職員が勤務先データのない既存顧客に会社名の情報を追加する' do
     customer.work_address.destroy
     click_link I18n.t('staff.top.dashboard.staff_customers')
     first('table.Table__body--listing').click_link I18n.t('staff.customers.index.edit')
@@ -124,4 +118,4 @@ feature 'Customer management by staff' do
     customer.reload
     expect(customer.work_address.company_name).to eq('テスト')
   end
-end
\ No newline at end of file
+end
diff --git a/spec/features/staff/phone_management_spec.rb b/spec/features/staff/phone_management_spec.rb
index 99935f2..0f97a6a 100644
--- a/spec/features/staff/phone_management_spec.rb
+++ b/spec/features/staff/phone_management_spec.rb
@@ -1,7 +1,6 @@
 require 'rails_helper'

-# 職員による顧客電話番号管理
-feature 'Customer telephone number management by staff' do
+feature '職員による顧客電話番号管理' do
   include FeaturesSpecHelper
   let(:staff_member) { create(:staff_member) }
   let!(:customer) { create(:customer) }
@@ -11,8 +10,7 @@ feature 'Customer telephone number management by staff' do
     login_as_staff_member(staff_member)
   end

-  # 職員が顧客の電話番号を追加する
-  scenario "The staff adds the customer's phone number" do
+  scenario '職員が顧客の電話番号を追加する' do
     click_link I18n.t('staff.top.dashboard.staff_customers')
     first('table.Table__body--listing').click_link I18n.t('staff.customers.index.edit')

@@ -25,8 +23,7 @@ feature 'Customer telephone number management by staff' do
     expect(customer.personal_phones[0].number).to eq('090-9999-9999')
   end

-  # 職員が顧客の自宅電話番号を追加する
-  scenario "The staff adds the customer's home phone number" do
+  scenario '職員が顧客の自宅電話番号を追加する' do
     click_link I18n.t('staff.top.dashboard.staff_customers')
     first('table.Table__body--listing').click_link I18n.t('staff.customers.index.edit')

@@ -39,8 +36,7 @@ feature 'Customer telephone number management by staff' do
     expect(customer.home_address.phones[0].number).to eq('090-9999-9999')
   end

-  # 職員が顧客の勤務先電話番号を追加する
-  scenario "The staff adds the customer's work phone number" do
+  scenario '職員が顧客の勤務先電話番号を追加する' do
     click_link I18n.t('staff.top.dashboard.staff_customers')
     first('table.Table__body--listing').click_link I18n.t('staff.customers.index.edit')

@@ -52,4 +48,4 @@ feature 'Customer telephone number management by staff' do
     expect(customer.work_address.phones.size).to eq(1)
     expect(customer.work_address.phones[0].number).to eq('03-9999-9999')
   end
-end
\ No newline at end of file
+end
diff --git a/spec/features/staff/program_management_spec.rb b/spec/features/staff/program_management_spec.rb
index 9131037..413731f 100644
--- a/spec/features/staff/program_management_spec.rb
+++ b/spec/features/staff/program_management_spec.rb
@@ -1,7 +1,6 @@
 require 'rails_helper'

-# プログラム管理機能
-feature 'Program management function', :performace do
+feature 'プログラム管理機能', :performace do
   include FeaturesSpecHelper
   include PerformanceSpecHelper
   let(:staff_member) { create(:staff_member) }
@@ -19,8 +18,7 @@ feature 'Program management function', :performace do
     login_as_staff_member(staff_member)
   end

-  # プログラム一覧
-  scenario 'Program list' do |example|
+  scenario 'プログラム一覧' do |example|
     visit staff_programs_path
     expect(page).to have_css('h1', text: I18n.t('staff.programs.index.title'))

@@ -34,4 +32,4 @@ feature 'Program management function', :performace do
     expect(elapsed).to be < 100.0
   end

-end
\ No newline at end of file
+end