allowOrderDataPages(); $cache = Mockery::mock(UpstreamQueryCache::class); $cache->shouldReceive('remember')->twice()->andReturnUsing( function (string $scope, array $parameters): array { if ($scope === 'order-data.after-sales.list') { $this->assertSame('ORDER-1', $parameters['filters']['order_no']); return ['rows' => [[ 'internal_order_no' => 'ORDER-1', 'shop_name' => '测试店铺', 'product_amount' => 123.45, ]]]; } $this->assertSame('order-data.promotion.list', $scope); return [ 'date' => '2026-08-09', 'rows' => [[ 'shop_name' => '推广测试店铺', 'product_code' => 'SKU-1', 'promotion_fee' => 9.05, ]], ]; }, ); $cache->shouldReceive('responseHeaders')->twice()->andReturn([ 'X-Caiwu-Data-Status' => 'direct', ]); $factory = Mockery::mock(UpstreamQueryCacheFactory::class); $factory->shouldReceive('forSource')->twice()->with('operations_replica')->andReturn($cache); $this->app->instance(UpstreamQueryCacheFactory::class, $factory); $afterSalesResponse = $this->loginAs() ->get(route('business.pages.show', [ 'section' => 'order-data', 'page' => 'after-sales-expenses', 'order_no' => 'ORDER-1', 'from' => '2026-08-01', 'to' => '2026-08-09', ])); $afterSalesResponse ->assertOk() ->assertSeeText('ORDER-1') ->assertSeeText('测试店铺') ->assertSeeText('123.45') ->assertSeeText('DIRECT') ->assertSeeText('导出当前页') ->assertSee('id="order-data-after-sales-export-button"', false) ->assertSee('data-export-contract="order-data.after-sales.current-page-export"', false) ->assertSee('data-export-table="order-data-after-sales-table"', false) ->assertSee('data-export-value="ORDER-1"', false) ->assertSee('data-export-value="123.45"', false) ->assertSee('data-export-number="true"', false) ->assertSee('window.setTimeout(() => {', false) ->assertSee('URL.revokeObjectURL(url);', false) ->assertSee('订单售后费用明细_2026-08-01_2026-08-09_第1页.csv', false); $this->get(route('business.pages.show', [ 'section' => 'order-data', 'page' => 'promotion-expenses', ])) ->assertOk() ->assertSeeText('推广测试店铺') ->assertSeeText('SKU-1') ->assertSeeText('9.05') ->assertSee('value="2026-08-09"', false); } public function test_order_data_page_keeps_rendering_when_the_upstream_is_unavailable(): void { $this->allowOrderDataPages(); $cache = Mockery::mock(UpstreamQueryCache::class); $cache->shouldReceive('remember')->once()->andThrow( new ServiceUnavailableHttpException(30, '首份共享快照正在准备。') ); $factory = Mockery::mock(UpstreamQueryCacheFactory::class); $factory->shouldReceive('forSource')->once()->with('operations_replica')->andReturn($cache); $this->app->instance(UpstreamQueryCacheFactory::class, $factory); $this->loginAs() ->get(route('business.pages.show', [ 'section' => 'order-data', 'page' => 'promotion-expenses', ])) ->assertOk() ->assertSeeText('首份共享快照正在准备。') ->assertSeeText('暂无数据'); } public function test_after_sales_export_is_disabled_when_the_current_page_has_no_rows(): void { $this->allowOrderDataPages(); $cache = Mockery::mock(UpstreamQueryCache::class); $cache->shouldReceive('remember')->once()->andReturn(['rows' => []]); $cache->shouldReceive('responseHeaders')->once()->andReturn([ 'X-Caiwu-Data-Status' => 'direct', ]); $factory = Mockery::mock(UpstreamQueryCacheFactory::class); $factory->shouldReceive('forSource')->once()->with('operations_replica')->andReturn($cache); $this->app->instance(UpstreamQueryCacheFactory::class, $factory); $this->loginAs() ->get(route('business.pages.show', [ 'section' => 'order-data', 'page' => 'after-sales-expenses', ])) ->assertOk() ->assertSeeText('导出当前页') ->assertSee('id="order-data-after-sales-export-button"', false) ->assertSee('disabled="disabled"', false); } private function allowOrderDataPages(): void { $this->user->update(['locale' => 'zh-CN']); $this->user->attachPermission( Permission::where('name', 'read-admin-panel')->firstOrFail() ); } }