ne_api 0.0.20 → 0.0.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e241f3b24f869c7bcb7050bbee61f91d7c0c99c11bda2518281c8dbde419b803
4
- data.tar.gz: a363f2cf97b9e42d46ca3ccab11f68a0ba54db984666f1e1e21c0988b16c3dd8
3
+ metadata.gz: 7c0274cd24bfbca15098ae69851b86bab0fd70bef4df5b802c42208525ddfb01
4
+ data.tar.gz: f1456cf436fd67297e14e30d3fd869279d69582ff77fd6b131f2d4acfd253f5c
5
5
  SHA512:
6
- metadata.gz: 1d9a90de06e6932495889e9df2894cc057a5d53f3f49f168792f4cb18ce1c40d20d199ebd7e47daa1b549dd691b572bd474302e32dac1ba83dcdb10f6886b746
7
- data.tar.gz: dc0c006a3f0aedda28f2dbdc290eddf8f053152f7adab62979e0256854925b6d5771deafba3eec13356e5cbf1869a5f7aaeb850be9c6fdecb762a8b5b2a80e0a
6
+ metadata.gz: c56d55baa11ef1e6b321d6de18e76cebb971837c74da56fde6f49d2292620c1a7d4dcbef49a7a8c1c9b8ee30cbc719a610ee66ac8b0dcb6c41222ff59950d5f1
7
+ data.tar.gz: 578330d042baf2e7de275f37bd07480be2368ef361828c7e1c8369bc0b8c71ef5da694f2bdc552cb1da3f0a32c14dbfda6b06d5f5122d474e6575478bf317faf
data/README.md CHANGED
@@ -103,6 +103,160 @@ end
103
103
 
104
104
  ```
105
105
 
106
+ ## Testing Support (RSpec)
107
+
108
+ ne_api provides built-in stub classes for testing in Rails applications.
109
+
110
+ ### Setup
111
+
112
+ Add to your `spec/rails_helper.rb`:
113
+
114
+ ```ruby
115
+ require 'ne_api/testing'
116
+
117
+ RSpec.configure do |config|
118
+ config.include NeAPI::Testing::RSpecHelpers
119
+ end
120
+ ```
121
+
122
+ ### Basic Usage
123
+
124
+ #### Using `with_fake_ne_api` block
125
+
126
+ ```ruby
127
+ RSpec.describe OrderSyncService do
128
+ it "syncs orders from Next Engine" do
129
+ with_fake_ne_api do |fake|
130
+ # Stub API responses
131
+ fake.stub(:receiveorder_base_search, [
132
+ ne_receive_order(receive_order_id: "ORDER001", receive_order_total_amount: 5000),
133
+ ne_receive_order(receive_order_id: "ORDER002", receive_order_total_amount: 3000)
134
+ ])
135
+
136
+ service = OrderSyncService.new
137
+ result = service.sync
138
+
139
+ expect(result.count).to eq 2
140
+ expect(fake.called?(:receiveorder_base_search)).to be true
141
+ expect(fake.call_count(:receiveorder_base_search)).to eq 1
142
+ end
143
+ end
144
+ end
145
+ ```
146
+
147
+ #### Direct injection (recommended for services with DI)
148
+
149
+ ```ruby
150
+ RSpec.describe StockService do
151
+ let(:fake_master) { fake_ne_master }
152
+
153
+ before do
154
+ fake_master.stub(:master_stock_search, [
155
+ ne_stock(stock_goods_id: "GOODS001", stock_quantity: 100)
156
+ ])
157
+ end
158
+
159
+ it "fetches stock data" do
160
+ service = StockService.new(ne_api: fake_master)
161
+ stocks = service.fetch_all
162
+
163
+ expect(stocks.first["stock_quantity"]).to eq 100
164
+ end
165
+ end
166
+ ```
167
+
168
+ ### Simulating Errors
169
+
170
+ ```ruby
171
+ it "handles API errors" do
172
+ with_fake_ne_api do |fake|
173
+ fake.simulate_error(code: "001001", message: "Authentication failed")
174
+
175
+ expect { service.sync }.to raise_error(NeAPIException, /001001/)
176
+ end
177
+ end
178
+ ```
179
+
180
+ ### Authentication Testing
181
+
182
+ ```ruby
183
+ RSpec.describe AuthController do
184
+ it "authenticates user" do
185
+ with_fake_ne_auth do |fake_auth|
186
+ fake_auth.stub_auth_response({
187
+ "access_token" => "custom_access_token",
188
+ "refresh_token" => "custom_refresh_token",
189
+ "company_ne_id" => "NE999999"
190
+ })
191
+
192
+ post :callback, params: { uid: "test_uid", state: "test_state" }
193
+
194
+ expect(session[:access_token]).to eq "custom_access_token"
195
+ end
196
+ end
197
+
198
+ it "handles authentication failure" do
199
+ with_fake_ne_auth do |fake_auth|
200
+ fake_auth.stub_auth_failure
201
+
202
+ expect {
203
+ post :callback, params: { uid: "test_uid", state: "test_state" }
204
+ }.to raise_error(NeAPIException)
205
+ end
206
+ end
207
+ end
208
+ ```
209
+
210
+ ### Available Factory Methods
211
+
212
+ | Method | Description |
213
+ |--------|-------------|
214
+ | `ne_goods(**attrs)` | Generate goods master data |
215
+ | `ne_goods_list(count)` | Generate list of goods |
216
+ | `ne_stock(**attrs)` | Generate stock data |
217
+ | `ne_stock_list(count)` | Generate list of stocks |
218
+ | `ne_receive_order(**attrs)` | Generate receive order data |
219
+ | `ne_receive_order_list(count)` | Generate list of orders |
220
+ | `ne_receive_order_row(**attrs)` | Generate order row data |
221
+ | `ne_shop(**attrs)` | Generate shop data |
222
+ | `ne_warehouse_stock(**attrs)` | Generate warehouse stock data |
223
+ | `ne_company_info(**attrs)` | Generate company info |
224
+ | `ne_user_info(**attrs)` | Generate user info |
225
+ | `ne_error(code:, message:)` | Generate error response |
226
+
227
+ ### FakeMaster Methods
228
+
229
+ | Method | Description |
230
+ |--------|-------------|
231
+ | `stub(method_name, response)` | Stub a specific API method |
232
+ | `simulate_error(code:, message:)` | Enable error mode |
233
+ | `clear_error` | Disable error mode |
234
+ | `reset!` | Clear all stubs and history |
235
+ | `called?(method_name)` | Check if method was called |
236
+ | `call_count(method_name)` | Get call count |
237
+ | `last_call_args(method_name)` | Get last call arguments |
238
+
239
+ ### Service Design for Testability
240
+
241
+ For best testability, design your services to accept `ne_api` as a dependency:
242
+
243
+ ```ruby
244
+ class OrderSyncService
245
+ def initialize(ne_api: nil)
246
+ @ne_api = ne_api || NeAPI::Master.new(
247
+ access_token: Rails.application.credentials.ne_access_token,
248
+ refresh_token: Rails.application.credentials.ne_refresh_token
249
+ )
250
+ end
251
+
252
+ def sync
253
+ @ne_api.receiveorder_base_search
254
+ end
255
+ end
256
+ ```
257
+
258
+ This allows easy injection of `FakeMaster` in tests.
259
+
106
260
  ## Contributing
107
261
 
108
262
  1. Fork it ( https://github.com/[my-github-username]/ne_api/fork )
@@ -112,6 +266,9 @@ end
112
266
  5. Create a new Pull Request
113
267
 
114
268
  ## Update
269
+ ### ver0.0.21
270
+ * 倉庫別の在庫などに対応
271
+ * rspecも作成
115
272
  ### ver0.0.18
116
273
  * 受注税金内訳取得APIに対応
117
274
  ### ver0.0.17
data/config/api.yaml CHANGED
@@ -309,3 +309,9 @@
309
309
  :prefix: warehouse_stock
310
310
  :fields: warehouse_id,goods_id,quantity,allocation_quantity,free_quantity
311
311
 
312
+ :warehouse_base:
313
+ :method
314
+ - count
315
+ - search
316
+ :prefix: warehouse
317
+ :fields: id,name,create_date
@@ -0,0 +1,109 @@
1
+ module NeAPI
2
+ module Testing
3
+ # NeAPI::Auth のスタブクラス
4
+ #
5
+ # @example 基本的な使い方
6
+ # fake = NeAPI::Testing::FakeAuth.new(redirect_url: "http://localhost:3000/callback")
7
+ # fake.ne_auth("uid123", "state456")
8
+ # fake.tokens #=> { access_token: "...", refresh_token: "..." }
9
+ #
10
+ # @example カスタムレスポンス
11
+ # fake.stub_auth_response({ "access_token" => "custom_token", ... })
12
+ # fake.ne_auth("uid", "state")
13
+ #
14
+ # @example 認証失敗のシミュレート
15
+ # fake.stub_auth_failure
16
+ # fake.ne_auth("uid", "state") #=> raises NeAPIException
17
+ #
18
+ class FakeAuth
19
+ attr_accessor :redirect_url, :ne_user, :wait_flag
20
+
21
+ def initialize(redirect_url: "http://localhost:3000/callback")
22
+ @redirect_url = redirect_url
23
+ @ne_user = nil
24
+ @wait_flag = false
25
+ @auth_response = nil
26
+ @should_fail = false
27
+ end
28
+
29
+ # 認証レスポンスをカスタマイズする
30
+ #
31
+ # @param response [Hash] 認証レスポンス
32
+ # @return [self]
33
+ def stub_auth_response(response)
34
+ @auth_response = response
35
+ self
36
+ end
37
+
38
+ # 認証失敗をシミュレートする
39
+ #
40
+ # @return [self]
41
+ def stub_auth_failure
42
+ @should_fail = true
43
+ self
44
+ end
45
+
46
+ # スタブをリセットする
47
+ #
48
+ # @return [self]
49
+ def reset!
50
+ @ne_user = nil
51
+ @auth_response = nil
52
+ @should_fail = false
53
+ self
54
+ end
55
+
56
+ # ブラウザを開かずにサインインURLを返す
57
+ #
58
+ # @param client_id [String] クライアントID
59
+ # @param client_secret [String] クライアントシークレット
60
+ # @return [String] コールバックURLの例
61
+ def sign_in(client_id = nil, client_secret = nil)
62
+ # 実際のブラウザは開かない
63
+ # テスト用にコールバックURLを返す
64
+ "#{@redirect_url}?uid=test_uid&state=test_state"
65
+ end
66
+
67
+ # 認証処理のスタブ
68
+ #
69
+ # @param uid [String] UID
70
+ # @param state [String] State
71
+ # @param client_id [String] クライアントID
72
+ # @param client_secret [String] クライアントシークレット
73
+ # @return [Hash] 認証レスポンス
74
+ # @raise [NeAPIException] 認証失敗時
75
+ def ne_auth(uid, state, client_id = nil, client_secret = nil)
76
+ raise NeAPIException, "003001:認証に失敗しました" if @should_fail
77
+
78
+ @ne_user = @auth_response || default_auth_response(uid)
79
+ end
80
+
81
+ # トークンを取得する
82
+ #
83
+ # @return [Hash, nil] トークン情報
84
+ def tokens
85
+ return nil if @ne_user.nil?
86
+
87
+ {
88
+ access_token: @ne_user["access_token"],
89
+ refresh_token: @ne_user["refresh_token"]
90
+ }
91
+ end
92
+
93
+ private
94
+
95
+ def default_auth_response(uid)
96
+ {
97
+ "result" => "success",
98
+ "uid" => uid,
99
+ "access_token" => "test_access_token_#{uid}",
100
+ "refresh_token" => "test_refresh_token_#{uid}",
101
+ "access_token_end_date" => (Time.now + 3600).strftime("%Y-%m-%d %H:%M:%S"),
102
+ "refresh_token_end_date" => (Time.now + 86400 * 30).strftime("%Y-%m-%d %H:%M:%S"),
103
+ "company_app_name" => "Test Company",
104
+ "company_ne_id" => "NE123456"
105
+ }
106
+ end
107
+ end
108
+ end
109
+ end
@@ -0,0 +1,177 @@
1
+ module NeAPI
2
+ module Testing
3
+ # NeAPI::Master のスタブクラス
4
+ #
5
+ # @example 基本的な使い方
6
+ # fake = NeAPI::Testing::FakeMaster.new
7
+ # fake.stub(:master_goods_search, [{ "goods_id" => "001" }])
8
+ # fake.master_goods_search #=> [{ "goods_id" => "001" }]
9
+ #
10
+ # @example エラーのシミュレート
11
+ # fake.simulate_error(code: "001001", message: "認証エラー")
12
+ # fake.master_goods_search #=> raises NeAPIException
13
+ #
14
+ class FakeMaster
15
+ attr_accessor :access_token, :refresh_token, :wait_flag, :retry_num, :wait_interval
16
+ attr_accessor :access_token_end_date, :refresh_token_end_date
17
+ attr_reader :call_history
18
+
19
+ def initialize(access_token: "test_access_token", refresh_token: "test_refresh_token")
20
+ @access_token = access_token
21
+ @refresh_token = refresh_token
22
+ @wait_flag = false
23
+ @retry_num = 10
24
+ @wait_interval = 15
25
+ @stubbed_responses = {}
26
+ @call_history = []
27
+ @error_mode = false
28
+ @error_code = nil
29
+ @error_message = nil
30
+ end
31
+
32
+ # 特定メソッドのレスポンスをスタブする
33
+ #
34
+ # @param method_name [Symbol, String] スタブするメソッド名
35
+ # @param response [Object] 返却するレスポンス(ブロックも可)
36
+ # @return [self]
37
+ def stub(method_name, response = nil, &block)
38
+ @stubbed_responses[method_name.to_sym] = block || -> (_) { response }
39
+ self
40
+ end
41
+
42
+ # エラーモードを有効にする
43
+ #
44
+ # @param code [String] エラーコード
45
+ # @param message [String] エラーメッセージ
46
+ # @return [self]
47
+ def simulate_error(code: "001001", message: "API Error")
48
+ @error_mode = true
49
+ @error_code = code
50
+ @error_message = message
51
+ self
52
+ end
53
+
54
+ # エラーモードを解除する
55
+ #
56
+ # @return [self]
57
+ def clear_error
58
+ @error_mode = false
59
+ @error_code = nil
60
+ @error_message = nil
61
+ self
62
+ end
63
+
64
+ # 全スタブと呼び出し履歴をクリアする
65
+ #
66
+ # @return [self]
67
+ def reset!
68
+ @stubbed_responses.clear
69
+ @call_history.clear
70
+ @error_mode = false
71
+ @error_code = nil
72
+ @error_message = nil
73
+ self
74
+ end
75
+
76
+ # 指定メソッドが呼び出されたかチェック
77
+ #
78
+ # @param method_name [Symbol, String] メソッド名
79
+ # @return [Boolean]
80
+ def called?(method_name)
81
+ @call_history.any? { |c| c[:method] == method_name.to_sym }
82
+ end
83
+
84
+ # 指定メソッドの呼び出し回数を取得
85
+ #
86
+ # @param method_name [Symbol, String] メソッド名
87
+ # @return [Integer]
88
+ def call_count(method_name)
89
+ @call_history.count { |c| c[:method] == method_name.to_sym }
90
+ end
91
+
92
+ # 指定メソッドの最後の呼び出し引数を取得
93
+ #
94
+ # @param method_name [Symbol, String] メソッド名
95
+ # @return [Hash, nil]
96
+ def last_call_args(method_name)
97
+ @call_history.reverse.find { |c| c[:method] == method_name.to_sym }&.[](:args)
98
+ end
99
+
100
+ # 強制インポートモード(本物と同じインターフェース)
101
+ def force_import
102
+ @wait_flag = true
103
+ end
104
+
105
+ def method_missing(method_name, args = {})
106
+ @call_history << { method: method_name.to_sym, args: args, time: Time.now }
107
+
108
+ if @error_mode
109
+ raise NeAPIException, "#{@error_code}:#{@error_message}"
110
+ end
111
+
112
+ if @stubbed_responses.key?(method_name.to_sym)
113
+ result = @stubbed_responses[method_name.to_sym].call(args)
114
+ wrap_response(result, method_name)
115
+ else
116
+ default_response(method_name, args)
117
+ end
118
+ end
119
+
120
+ def respond_to_missing?(method_name, include_private = false)
121
+ true
122
+ end
123
+
124
+ private
125
+
126
+ def wrap_response(data, method_name)
127
+ # 既にHash形式でresultキーがある場合はそのまま返す
128
+ return data if data.is_a?(Hash) && data.key?("result")
129
+
130
+ method_type = method_name.to_s.split("_").last
131
+ case method_type
132
+ when "search"
133
+ # searchはdataキーの値を直接返す
134
+ data
135
+ when "count"
136
+ data.is_a?(Integer) ? data.to_s : data
137
+ else
138
+ data
139
+ end
140
+ end
141
+
142
+ def default_response(method_name, args)
143
+ method_type = method_name.to_s.split("_").last
144
+ case method_type
145
+ when "search"
146
+ []
147
+ when "count"
148
+ "0"
149
+ when "info"
150
+ {
151
+ "result" => "success",
152
+ "data" => [],
153
+ "count" => "0",
154
+ "access_token" => @access_token,
155
+ "refresh_token" => @refresh_token
156
+ }
157
+ when "update", "upload", "receipted", "shipped", "labelprinted", "add", "bulkupdate", "bulkupdatereceipted"
158
+ "success"
159
+ when "divide"
160
+ "new_receive_order_id"
161
+ when "checkconnect"
162
+ {
163
+ "result" => "success",
164
+ "access_token" => @access_token,
165
+ "refresh_token" => @refresh_token
166
+ }
167
+ else
168
+ {
169
+ "result" => "success",
170
+ "access_token" => @access_token,
171
+ "refresh_token" => @refresh_token
172
+ }
173
+ end
174
+ end
175
+ end
176
+ end
177
+ end
@@ -0,0 +1,227 @@
1
+ require 'securerandom'
2
+
3
+ module NeAPI
4
+ module Testing
5
+ # テスト用レスポンスデータを生成するファクトリ
6
+ #
7
+ # @example 商品データ生成
8
+ # ResponseFactory.goods(goods_name: "テスト商品A")
9
+ # ResponseFactory.goods_list(3)
10
+ #
11
+ # @example 受注データ生成
12
+ # ResponseFactory.receive_order(receive_order_total_amount: 5000)
13
+ #
14
+ class ResponseFactory
15
+ class << self
16
+ # 商品マスタデータを生成
17
+ #
18
+ # @param overrides [Hash] 上書きする属性
19
+ # @return [Hash]
20
+ def goods(overrides = {})
21
+ {
22
+ "goods_id" => SecureRandom.hex(8),
23
+ "goods_name" => "テスト商品",
24
+ "goods_jan_code" => "4912345678901"
25
+ }.merge(stringify_keys(overrides))
26
+ end
27
+
28
+ # 商品リストを生成
29
+ #
30
+ # @param count [Integer] 生成数
31
+ # @yield [item, index] 各アイテムをカスタマイズするブロック
32
+ # @return [Array<Hash>]
33
+ def goods_list(count = 3, &block)
34
+ count.times.map do |i|
35
+ item = goods("goods_id" => "GOODS#{format('%03d', i + 1)}", "goods_name" => "テスト商品#{i + 1}")
36
+ block ? block.call(item, i) : item
37
+ end
38
+ end
39
+
40
+ # 在庫マスタデータを生成
41
+ #
42
+ # @param overrides [Hash] 上書きする属性
43
+ # @return [Hash]
44
+ def stock(overrides = {})
45
+ {
46
+ "stock_goods_id" => SecureRandom.hex(8),
47
+ "stock_quantity" => 100,
48
+ "stock_allocation_quantity" => 10,
49
+ "stock_defective_quantity" => 0,
50
+ "stock_remaining_order_quantity" => 0,
51
+ "stock_out_quantity" => 0,
52
+ "stock_free_quantity" => 90
53
+ }.merge(stringify_keys(overrides))
54
+ end
55
+
56
+ # 在庫リストを生成
57
+ #
58
+ # @param count [Integer] 生成数
59
+ # @return [Array<Hash>]
60
+ def stock_list(count = 3, &block)
61
+ count.times.map do |i|
62
+ item = stock("stock_goods_id" => "GOODS#{format('%03d', i + 1)}")
63
+ block ? block.call(item, i) : item
64
+ end
65
+ end
66
+
67
+ # 受注データを生成
68
+ #
69
+ # @param overrides [Hash] 上書きする属性
70
+ # @return [Hash]
71
+ def receive_order(overrides = {})
72
+ {
73
+ "receive_order_id" => SecureRandom.hex(8),
74
+ "receive_order_shop_id" => "1",
75
+ "receive_order_shop_cut_form_id" => "ORD-#{SecureRandom.hex(4).upcase}",
76
+ "receive_order_date" => Time.now.strftime("%Y-%m-%d %H:%M:%S"),
77
+ "receive_order_order_status_id" => "10",
78
+ "receive_order_order_status_name" => "新規受付",
79
+ "receive_order_delivery_id" => "1",
80
+ "receive_order_delivery_name" => "ヤマト運輸",
81
+ "receive_order_payment_method_id" => "1",
82
+ "receive_order_payment_method_name" => "クレジットカード",
83
+ "receive_order_total_amount" => 1000,
84
+ "receive_order_tax_amount" => 100,
85
+ "receive_order_goods_amount" => 900,
86
+ "receive_order_delivery_fee_amount" => 0,
87
+ "receive_order_purchaser_name" => "テスト顧客",
88
+ "receive_order_purchaser_kana" => "テストコキャク",
89
+ "receive_order_purchaser_zip_code" => "100-0001",
90
+ "receive_order_purchaser_address1" => "東京都千代田区",
91
+ "receive_order_purchaser_address2" => "1-1-1",
92
+ "receive_order_purchaser_tel" => "03-1234-5678",
93
+ "receive_order_purchaser_mail_address" => "test@example.com",
94
+ "receive_order_consignee_name" => "テスト顧客",
95
+ "receive_order_consignee_zip_code" => "100-0001",
96
+ "receive_order_consignee_address1" => "東京都千代田区",
97
+ "receive_order_consignee_address2" => "1-1-1",
98
+ "receive_order_consignee_tel" => "03-1234-5678"
99
+ }.merge(stringify_keys(overrides))
100
+ end
101
+
102
+ # 受注リストを生成
103
+ #
104
+ # @param count [Integer] 生成数
105
+ # @return [Array<Hash>]
106
+ def receive_order_list(count = 3, &block)
107
+ count.times.map do |i|
108
+ item = receive_order("receive_order_shop_cut_form_id" => "ORD-#{format('%04d', i + 1)}")
109
+ block ? block.call(item, i) : item
110
+ end
111
+ end
112
+
113
+ # 受注明細データを生成
114
+ #
115
+ # @param overrides [Hash] 上書きする属性
116
+ # @return [Hash]
117
+ def receive_order_row(overrides = {})
118
+ {
119
+ "receive_order_row_receive_order_id" => SecureRandom.hex(8),
120
+ "receive_order_row_no" => "1",
121
+ "receive_order_row_goods_id" => SecureRandom.hex(8),
122
+ "receive_order_row_goods_name" => "テスト商品",
123
+ "receive_order_row_quantity" => 1,
124
+ "receive_order_row_unit_price" => 1000,
125
+ "receive_order_row_goods_option" => ""
126
+ }.merge(stringify_keys(overrides))
127
+ end
128
+
129
+ # 会社情報を生成
130
+ #
131
+ # @param overrides [Hash] 上書きする属性
132
+ # @return [Hash]
133
+ def company_info(overrides = {})
134
+ {
135
+ "company_id" => "12345",
136
+ "company_name" => "テスト会社",
137
+ "company_ne_id" => "NE123456",
138
+ "company_kana" => "テストカイシャ"
139
+ }.merge(stringify_keys(overrides))
140
+ end
141
+
142
+ # ユーザー情報を生成
143
+ #
144
+ # @param overrides [Hash] 上書きする属性
145
+ # @return [Hash]
146
+ def user_info(overrides = {})
147
+ {
148
+ "user_id" => "1",
149
+ "user_name" => "テストユーザー",
150
+ "user_mail" => "test@example.com"
151
+ }.merge(stringify_keys(overrides))
152
+ end
153
+
154
+ # 店舗データを生成
155
+ #
156
+ # @param overrides [Hash] 上書きする属性
157
+ # @return [Hash]
158
+ def shop(overrides = {})
159
+ {
160
+ "shop_id" => "1",
161
+ "shop_name" => "テスト店舗",
162
+ "shop_kana" => "テストテンポ",
163
+ "shop_abbreviated_name" => "テスト",
164
+ "shop_mall_id" => "1",
165
+ "shop_deleted_flag" => "0"
166
+ }.merge(stringify_keys(overrides))
167
+ end
168
+
169
+ # 倉庫在庫データを生成
170
+ #
171
+ # @param overrides [Hash] 上書きする属性
172
+ # @return [Hash]
173
+ def warehouse_stock(overrides = {})
174
+ {
175
+ "warehouse_stock_warehouse_id" => "1",
176
+ "warehouse_stock_goods_id" => SecureRandom.hex(8),
177
+ "warehouse_stock_quantity" => 100,
178
+ "warehouse_stock_allocation_quantity" => 10,
179
+ "warehouse_stock_free_quantity" => 90
180
+ }.merge(stringify_keys(overrides))
181
+ end
182
+
183
+ # エラーレスポンスを生成
184
+ #
185
+ # @param code [String] エラーコード
186
+ # @param message [String] エラーメッセージ
187
+ # @return [Hash]
188
+ def error(code: "001001", message: "エラーが発生しました")
189
+ {
190
+ "result" => "error",
191
+ "code" => code,
192
+ "message" => message
193
+ }
194
+ end
195
+
196
+ # 混雑エラー(リトライ対象)を生成
197
+ #
198
+ # @return [Hash]
199
+ def busy_error
200
+ error(code: "003001", message: "Next Engineが大変混み合っています")
201
+ end
202
+
203
+ # 成功レスポンスを生成(info系API用)
204
+ #
205
+ # @param data [Array] データ配列
206
+ # @param access_token [String] アクセストークン
207
+ # @param refresh_token [String] リフレッシュトークン
208
+ # @return [Hash]
209
+ def success_response(data: [], access_token: "test_access_token", refresh_token: "test_refresh_token")
210
+ {
211
+ "result" => "success",
212
+ "data" => data,
213
+ "count" => data.size.to_s,
214
+ "access_token" => access_token,
215
+ "refresh_token" => refresh_token
216
+ }
217
+ end
218
+
219
+ private
220
+
221
+ def stringify_keys(hash)
222
+ hash.transform_keys(&:to_s)
223
+ end
224
+ end
225
+ end
226
+ end
227
+ end
@@ -0,0 +1,154 @@
1
+ module NeAPI
2
+ module Testing
3
+ # RSpec用ヘルパーメソッド
4
+ #
5
+ # @example spec/rails_helper.rb での設定
6
+ # require 'ne_api/testing'
7
+ #
8
+ # RSpec.configure do |config|
9
+ # config.include NeAPI::Testing::RSpecHelpers
10
+ # end
11
+ #
12
+ # @example テストコードでの使用
13
+ # RSpec.describe OrderService do
14
+ # it "受注を取得する" do
15
+ # with_fake_ne_api do |fake|
16
+ # fake.stub(:receiveorder_base_search, [ne_receive_order])
17
+ # # ...
18
+ # end
19
+ # end
20
+ # end
21
+ #
22
+ module RSpecHelpers
23
+ # FakeMasterインスタンスを生成
24
+ #
25
+ # @param options [Hash] 初期化オプション
26
+ # @return [FakeMaster]
27
+ def fake_ne_master(**options)
28
+ NeAPI::Testing::FakeMaster.new(**options)
29
+ end
30
+
31
+ # FakeAuthインスタンスを生成
32
+ #
33
+ # @param options [Hash] 初期化オプション
34
+ # @return [FakeAuth]
35
+ def fake_ne_auth(**options)
36
+ NeAPI::Testing::FakeAuth.new(**options)
37
+ end
38
+
39
+ # NeAPI::Master.newをFakeMasterに差し替えてブロックを実行
40
+ #
41
+ # @yield [FakeMaster] FakeMasterインスタンス
42
+ # @return [Object] ブロックの戻り値
43
+ #
44
+ # @example
45
+ # with_fake_ne_api do |fake|
46
+ # fake.stub(:master_goods_search, [ne_goods])
47
+ # service = MyService.new # 内部でNeAPI::Master.newを呼ぶ
48
+ # service.call
49
+ # end
50
+ def with_fake_ne_api(**options)
51
+ fake = fake_ne_master(**options)
52
+ allow(NeAPI::Master).to receive(:new).and_return(fake)
53
+ yield fake
54
+ end
55
+
56
+ # NeAPI::Auth.newをFakeAuthに差し替えてブロックを実行
57
+ #
58
+ # @yield [FakeAuth] FakeAuthインスタンス
59
+ # @return [Object] ブロックの戻り値
60
+ def with_fake_ne_auth(**options)
61
+ fake = fake_ne_auth(**options)
62
+ allow(NeAPI::Auth).to receive(:new).and_return(fake)
63
+ yield fake
64
+ end
65
+
66
+ # --- ResponseFactoryへのショートカット ---
67
+
68
+ # 商品データを生成
69
+ # @see ResponseFactory.goods
70
+ def ne_goods(**attrs)
71
+ NeAPI::Testing::ResponseFactory.goods(attrs)
72
+ end
73
+
74
+ # 商品リストを生成
75
+ # @see ResponseFactory.goods_list
76
+ def ne_goods_list(count = 3, &block)
77
+ NeAPI::Testing::ResponseFactory.goods_list(count, &block)
78
+ end
79
+
80
+ # 在庫データを生成
81
+ # @see ResponseFactory.stock
82
+ def ne_stock(**attrs)
83
+ NeAPI::Testing::ResponseFactory.stock(attrs)
84
+ end
85
+
86
+ # 在庫リストを生成
87
+ # @see ResponseFactory.stock_list
88
+ def ne_stock_list(count = 3, &block)
89
+ NeAPI::Testing::ResponseFactory.stock_list(count, &block)
90
+ end
91
+
92
+ # 受注データを生成
93
+ # @see ResponseFactory.receive_order
94
+ def ne_receive_order(**attrs)
95
+ NeAPI::Testing::ResponseFactory.receive_order(attrs)
96
+ end
97
+
98
+ # 受注リストを生成
99
+ # @see ResponseFactory.receive_order_list
100
+ def ne_receive_order_list(count = 3, &block)
101
+ NeAPI::Testing::ResponseFactory.receive_order_list(count, &block)
102
+ end
103
+
104
+ # 受注明細データを生成
105
+ # @see ResponseFactory.receive_order_row
106
+ def ne_receive_order_row(**attrs)
107
+ NeAPI::Testing::ResponseFactory.receive_order_row(attrs)
108
+ end
109
+
110
+ # 会社情報を生成
111
+ # @see ResponseFactory.company_info
112
+ def ne_company_info(**attrs)
113
+ NeAPI::Testing::ResponseFactory.company_info(attrs)
114
+ end
115
+
116
+ # ユーザー情報を生成
117
+ # @see ResponseFactory.user_info
118
+ def ne_user_info(**attrs)
119
+ NeAPI::Testing::ResponseFactory.user_info(attrs)
120
+ end
121
+
122
+ # 店舗データを生成
123
+ # @see ResponseFactory.shop
124
+ def ne_shop(**attrs)
125
+ NeAPI::Testing::ResponseFactory.shop(attrs)
126
+ end
127
+
128
+ # 倉庫在庫データを生成
129
+ # @see ResponseFactory.warehouse_stock
130
+ def ne_warehouse_stock(**attrs)
131
+ NeAPI::Testing::ResponseFactory.warehouse_stock(attrs)
132
+ end
133
+
134
+ # エラーレスポンスを生成
135
+ # @see ResponseFactory.error
136
+ def ne_error(**attrs)
137
+ NeAPI::Testing::ResponseFactory.error(**attrs)
138
+ end
139
+
140
+ # 成功レスポンスを生成
141
+ # @see ResponseFactory.success_response
142
+ def ne_success_response(**attrs)
143
+ NeAPI::Testing::ResponseFactory.success_response(**attrs)
144
+ end
145
+ end
146
+ end
147
+ end
148
+
149
+ # RSpecが読み込まれていれば自動設定
150
+ if defined?(RSpec)
151
+ RSpec.configure do |config|
152
+ config.include NeAPI::Testing::RSpecHelpers
153
+ end
154
+ end
@@ -0,0 +1,44 @@
1
+ # ne_api テスト用スタブ
2
+ #
3
+ # Railsプロジェクトでの設定:
4
+ #
5
+ # # spec/rails_helper.rb
6
+ # require 'ne_api/testing'
7
+ #
8
+ # RSpec.configure do |config|
9
+ # config.include NeAPI::Testing::RSpecHelpers
10
+ # end
11
+ #
12
+ # 使用例:
13
+ #
14
+ # RSpec.describe OrderSyncService do
15
+ # it "受注を同期する" do
16
+ # with_fake_ne_api do |fake|
17
+ # fake.stub(:receiveorder_base_search, [
18
+ # ne_receive_order(receive_order_id: "ORDER001")
19
+ # ])
20
+ #
21
+ # service = OrderSyncService.new(ne_api: fake)
22
+ # result = service.sync
23
+ #
24
+ # expect(result.count).to eq 1
25
+ # expect(fake.called?(:receiveorder_base_search)).to be true
26
+ # end
27
+ # end
28
+ # end
29
+
30
+ require_relative 'testing/fake_master'
31
+ require_relative 'testing/fake_auth'
32
+ require_relative 'testing/response_factory'
33
+ require_relative 'testing/rspec_helpers'
34
+
35
+ module NeAPI
36
+ module Testing
37
+ class << self
38
+ # 設定用ブロック(将来の拡張用)
39
+ def configure
40
+ yield self if block_given?
41
+ end
42
+ end
43
+ end
44
+ end
@@ -1,3 +1,3 @@
1
1
  module NeApi
2
- VERSION = "0.0.20"
2
+ VERSION = "0.0.21"
3
3
  end
metadata CHANGED
@@ -1,15 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ne_api
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.20
4
+ version: 0.0.21
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yuuna Kurita
8
8
  - Mika Koizumi
9
- autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2023-12-29 00:00:00.000000000 Z
11
+ date: 1980-01-02 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: bundler
@@ -152,6 +151,11 @@ files:
152
151
  - Rakefile
153
152
  - config/api.yaml
154
153
  - lib/ne_api.rb
154
+ - lib/ne_api/testing.rb
155
+ - lib/ne_api/testing/fake_auth.rb
156
+ - lib/ne_api/testing/fake_master.rb
157
+ - lib/ne_api/testing/response_factory.rb
158
+ - lib/ne_api/testing/rspec_helpers.rb
155
159
  - lib/ne_api/version.rb
156
160
  - ne_api.gemspec
157
161
  - spec/ne_api_spec.rb
@@ -159,7 +163,6 @@ homepage: http://github.com/infinity-octaver/ne_api/
159
163
  licenses:
160
164
  - MIT
161
165
  metadata: {}
162
- post_install_message:
163
166
  rdoc_options: []
164
167
  require_paths:
165
168
  - lib
@@ -174,8 +177,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
174
177
  - !ruby/object:Gem::Version
175
178
  version: '0'
176
179
  requirements: []
177
- rubygems_version: 3.1.6
178
- signing_key:
180
+ rubygems_version: 4.0.1
179
181
  specification_version: 4
180
182
  summary: Next Engine API for ruby
181
183
  test_files: