Bring feature work for OperationRun phase composite progress into `platform-dev`. This PR contains the merged session commits and spec artifacts. Notes: - Session branch was merged into `272-operationrun-phase-composite-progress` locally and pushed. - Please review specs and tests under `specs/272-operationrun-phase-composite-progress/`. Co-authored-by: Ahmed Darrazi <ahmed.darrazi@live.de> Reviewed-on: #330
548 lines
21 KiB
PHP
548 lines
21 KiB
PHP
<?php
|
|
|
|
use App\Filament\Resources\InventoryItemResource;
|
|
use App\Livewire\BulkOperationProgress;
|
|
use App\Models\OperationRun;
|
|
use App\Support\OpsUx\OperationRunUrl;
|
|
use Filament\Facades\Filament;
|
|
use Livewire\Livewire;
|
|
|
|
it('renders three visible run summaries while grouping banner actions in one action area', function (): void {
|
|
[$user, $tenant] = createUserWithTenant(role: 'owner');
|
|
|
|
$this->actingAs($user);
|
|
Filament::setTenant($tenant, true);
|
|
|
|
$firstRun = null;
|
|
|
|
foreach (range(0, 3) as $offset) {
|
|
$run = OperationRun::factory()->create([
|
|
'tenant_id' => (int) $tenant->getKey(),
|
|
'workspace_id' => (int) $tenant->workspace_id,
|
|
'user_id' => (int) $user->getKey(),
|
|
'type' => 'inventory_sync',
|
|
'status' => 'queued',
|
|
'outcome' => 'pending',
|
|
'created_at' => now()->subMinutes($offset),
|
|
]);
|
|
|
|
if ($offset === 0) {
|
|
$firstRun = $run;
|
|
}
|
|
}
|
|
|
|
$component = Livewire::actingAs($user)
|
|
->test(BulkOperationProgress::class)
|
|
->call('refreshRuns');
|
|
|
|
$html = $component->html();
|
|
$pageText = preg_replace('/\s+/', ' ', strip_tags($html));
|
|
|
|
expect(substr_count($html, 'data-testid="ops-ux-activity-feedback-item"'))->toBe(3)
|
|
->and($html)->toContain('Active operations')
|
|
->and($pageText)->toContain('Queued and running work stays here until diagnostics are needed.')
|
|
->and(substr_count($html, 'Review operations'))->toBe(1)
|
|
->and(substr_count($html, 'View operation'))->toBe(0)
|
|
->and($html)->toContain('data-testid="ops-ux-activity-feedback-actions"')
|
|
->and($html)->toContain('data-testid="ops-ux-activity-feedback-primary-action"')
|
|
->and($html)->toContain('Show all operations')
|
|
->and($html)->toContain('Hide activity')
|
|
->and($html)->not->toContain('Dismiss')
|
|
->and($html)->not->toContain('Acknowledge')
|
|
->and($html)->toContain(OperationRunUrl::index($tenant))
|
|
->and($html)->not->toContain($firstRun instanceof OperationRun ? OperationRunUrl::view($firstRun, $tenant) : '')
|
|
->and($html)->not->toContain('Open operation');
|
|
})->group('ops-ux');
|
|
|
|
it('renders a single visible operation with a detail primary action', function (): void {
|
|
[$user, $tenant] = createUserWithTenant(role: 'owner');
|
|
|
|
$this->actingAs($user);
|
|
Filament::setTenant($tenant, true);
|
|
|
|
$run = OperationRun::factory()->create([
|
|
'tenant_id' => (int) $tenant->getKey(),
|
|
'workspace_id' => (int) $tenant->workspace_id,
|
|
'user_id' => (int) $user->getKey(),
|
|
'type' => 'inventory_sync',
|
|
'status' => 'queued',
|
|
'outcome' => 'pending',
|
|
'created_at' => now()->subSeconds(10),
|
|
]);
|
|
|
|
$component = Livewire::actingAs($user)
|
|
->test(BulkOperationProgress::class)
|
|
->call('refreshRuns');
|
|
|
|
$html = $component->html();
|
|
$pageText = preg_replace('/\s+/', ' ', strip_tags($html));
|
|
|
|
expect(substr_count($html, 'data-testid="ops-ux-activity-feedback-item"'))->toBe(1)
|
|
->and($html)->toContain('Active operations')
|
|
->and($pageText)->toContain('Queued and running work stays here until diagnostics are needed.')
|
|
->and(substr_count($html, 'View operation'))->toBe(1)
|
|
->and($html)->not->toContain('Review operations')
|
|
->and($html)->toContain(OperationRunUrl::view($run, $tenant))
|
|
->and($html)->toContain(OperationRunUrl::index($tenant))
|
|
->and($html)->toContain('Hide activity')
|
|
->and($html)->not->toContain('Dismiss')
|
|
->and($html)->not->toContain('Acknowledge');
|
|
})->group('ops-ux');
|
|
|
|
it('renders a recent terminal success state with dismiss instead of hide activity', function (): void {
|
|
[$user, $tenant] = createUserWithTenant(role: 'owner');
|
|
|
|
$this->actingAs($user);
|
|
Filament::setTenant($tenant, true);
|
|
|
|
OperationRun::factory()->create([
|
|
'tenant_id' => (int) $tenant->getKey(),
|
|
'workspace_id' => (int) $tenant->workspace_id,
|
|
'user_id' => (int) $user->getKey(),
|
|
'type' => 'inventory_sync',
|
|
'status' => 'completed',
|
|
'outcome' => 'succeeded',
|
|
'started_at' => now()->subMinutes(2),
|
|
'completed_at' => now()->subSeconds(8),
|
|
'summary_counts' => [
|
|
'total' => 10,
|
|
'processed' => 10,
|
|
],
|
|
]);
|
|
|
|
$component = Livewire::actingAs($user)
|
|
->test(BulkOperationProgress::class)
|
|
->call('refreshRuns');
|
|
|
|
$html = html_entity_decode($component->html(), ENT_QUOTES | ENT_HTML5);
|
|
$pageText = preg_replace('/\s+/', ' ', strip_tags($html));
|
|
|
|
expect($component->get('hasActiveRuns'))->toBeFalse()
|
|
->and($html)->toContain('Operation updates')
|
|
->and($pageText)->toContain('Recent operation updates.')
|
|
->and($pageText)->toContain('Completed successfully')
|
|
->and($pageText)->toContain('No action needed.')
|
|
->and($html)->toContain('View operation')
|
|
->and($html)->not->toContain('Review operations')
|
|
->and($html)->toContain('Dismiss')
|
|
->and($html)->not->toContain('Hide activity')
|
|
->and($html)->not->toContain('data-testid="ops-ux-activity-feedback-indeterminate"')
|
|
->and($html)->not->toContain('role="progressbar"');
|
|
})->group('ops-ux');
|
|
|
|
it('renders terminal follow-up states with dismiss instead of hide activity', function (): void {
|
|
[$user, $tenant] = createUserWithTenant(role: 'owner');
|
|
|
|
$this->actingAs($user);
|
|
Filament::setTenant($tenant, true);
|
|
|
|
OperationRun::factory()->create([
|
|
'tenant_id' => (int) $tenant->getKey(),
|
|
'workspace_id' => (int) $tenant->workspace_id,
|
|
'user_id' => (int) $user->getKey(),
|
|
'type' => 'inventory_sync',
|
|
'status' => 'completed',
|
|
'outcome' => 'failed',
|
|
'started_at' => now()->subMinutes(3),
|
|
'completed_at' => now()->subSeconds(6),
|
|
]);
|
|
|
|
$component = Livewire::actingAs($user)
|
|
->test(BulkOperationProgress::class)
|
|
->call('refreshRuns');
|
|
|
|
$html = html_entity_decode($component->html(), ENT_QUOTES | ENT_HTML5);
|
|
$pageText = preg_replace('/\s+/', ' ', strip_tags($html));
|
|
|
|
expect($component->get('hasActiveRuns'))->toBeFalse()
|
|
->and($html)->toContain('Operation updates')
|
|
->and($pageText)->toContain('Recent operation updates that may need review.')
|
|
->and($html)->toContain('View operation')
|
|
->and($html)->not->toContain('Review operations')
|
|
->and($html)->toContain('Dismiss')
|
|
->and($html)->not->toContain('Acknowledge')
|
|
->and($html)->not->toContain('data-testid="ops-ux-activity-feedback-indeterminate"')
|
|
->and($html)->not->toContain('role="progressbar"')
|
|
->and($html)->not->toContain('Hide activity');
|
|
})->group('ops-ux');
|
|
|
|
it('uses a collective primary action when active and terminal follow-up items are both visible', function (): void {
|
|
[$user, $tenant] = createUserWithTenant(role: 'owner');
|
|
|
|
$this->actingAs($user);
|
|
Filament::setTenant($tenant, true);
|
|
|
|
$runningRun = OperationRun::factory()->create([
|
|
'tenant_id' => (int) $tenant->getKey(),
|
|
'workspace_id' => (int) $tenant->workspace_id,
|
|
'user_id' => (int) $user->getKey(),
|
|
'type' => 'inventory_sync',
|
|
'status' => 'running',
|
|
'outcome' => 'pending',
|
|
'started_at' => now()->subMinute(),
|
|
]);
|
|
|
|
OperationRun::factory()->create([
|
|
'tenant_id' => (int) $tenant->getKey(),
|
|
'workspace_id' => (int) $tenant->workspace_id,
|
|
'user_id' => (int) $user->getKey(),
|
|
'type' => 'inventory_sync',
|
|
'status' => 'completed',
|
|
'outcome' => 'failed',
|
|
'started_at' => now()->subMinutes(3),
|
|
'completed_at' => now()->subSeconds(6),
|
|
]);
|
|
|
|
$component = Livewire::actingAs($user)
|
|
->test(BulkOperationProgress::class)
|
|
->call('refreshRuns');
|
|
|
|
$html = html_entity_decode($component->html(), ENT_QUOTES | ENT_HTML5);
|
|
$pageText = preg_replace('/\s+/', ' ', strip_tags($html));
|
|
|
|
expect($html)->toContain('Review operations')
|
|
->and($html)->toContain('Operation updates')
|
|
->and($pageText)->toContain('Active and recent operation updates that may need review.')
|
|
->and($html)->not->toContain('View operation')
|
|
->and($html)->toContain('Hide activity')
|
|
->and($html)->toContain(OperationRunUrl::index($tenant))
|
|
->and($html)->not->toContain(OperationRunUrl::view($runningRun, $tenant))
|
|
->and($pageText)->toContain('Execution failed');
|
|
})->group('ops-ux');
|
|
|
|
it('renders an indeterminate running indicator when processed totals are not trustworthy', function (): void {
|
|
[$user, $tenant] = createUserWithTenant(role: 'owner');
|
|
|
|
$this->actingAs($user);
|
|
Filament::setTenant($tenant, true);
|
|
|
|
OperationRun::factory()->create([
|
|
'tenant_id' => (int) $tenant->getKey(),
|
|
'workspace_id' => (int) $tenant->workspace_id,
|
|
'user_id' => (int) $user->getKey(),
|
|
'type' => 'inventory_sync',
|
|
'status' => 'running',
|
|
'outcome' => 'pending',
|
|
'summary_counts' => [
|
|
'processed' => 4,
|
|
],
|
|
'started_at' => now()->subMinute(),
|
|
]);
|
|
|
|
$component = Livewire::actingAs($user)
|
|
->test(BulkOperationProgress::class)
|
|
->call('refreshRuns');
|
|
|
|
$html = html_entity_decode($component->html(), ENT_QUOTES | ENT_HTML5);
|
|
$pageText = preg_replace('/\s+/', ' ', strip_tags($html));
|
|
|
|
expect($html)->toContain('data-testid="ops-ux-activity-feedback-indeterminate"')
|
|
->and($html)->toContain('Active operations')
|
|
->and($pageText)->toMatch('/Running · .* · Progress details pending\./')
|
|
->and($html)->not->toContain('role="progressbar"')
|
|
->and($html)->toContain('View operation')
|
|
->and($html)->not->toContain('Review operations')
|
|
->and($html)->toContain('Hide activity');
|
|
})->group('ops-ux');
|
|
|
|
it('shows determinate progress with truthful processed totals and percent when summary counts are valid', function (): void {
|
|
[$user, $tenant] = createUserWithTenant(role: 'owner');
|
|
|
|
$this->actingAs($user);
|
|
Filament::setTenant($tenant, true);
|
|
|
|
OperationRun::factory()->create([
|
|
'tenant_id' => (int) $tenant->getKey(),
|
|
'workspace_id' => (int) $tenant->workspace_id,
|
|
'user_id' => (int) $user->getKey(),
|
|
'type' => 'inventory_sync',
|
|
'status' => 'running',
|
|
'outcome' => 'pending',
|
|
'summary_counts' => [
|
|
'total' => 10,
|
|
'processed' => 4,
|
|
],
|
|
'started_at' => now()->subWeeks(2),
|
|
]);
|
|
|
|
$component = Livewire::actingAs($user)
|
|
->test(BulkOperationProgress::class)
|
|
->call('refreshRuns');
|
|
|
|
$html = html_entity_decode($component->html(), ENT_QUOTES | ENT_HTML5);
|
|
$pageText = preg_replace('/\s+/', ' ', strip_tags($html));
|
|
|
|
expect($html)->toContain('role="progressbar"')
|
|
->and($html)->toContain('aria-valuenow="40"')
|
|
->and($html)->toContain('Active operations')
|
|
->and($pageText)->toMatch('/Running · .* · 4 \/ 10 processed \(40%\)/')
|
|
->and($html)->toContain('View operation')
|
|
->and($html)->not->toContain('Review operations')
|
|
->and($html)->not->toContain('data-testid="ops-ux-activity-feedback-indeterminate"')
|
|
->and($html)->not->toContain('Likely stale');
|
|
})->group('ops-ux');
|
|
|
|
it('renders phased fallback progress without inventing a counted percentage', function (): void {
|
|
[$user, $tenant] = createUserWithTenant(role: 'owner');
|
|
|
|
$this->actingAs($user);
|
|
Filament::setTenant($tenant, true);
|
|
|
|
OperationRun::factory()->create([
|
|
'tenant_id' => (int) $tenant->getKey(),
|
|
'workspace_id' => (int) $tenant->workspace_id,
|
|
'user_id' => (int) $user->getKey(),
|
|
'type' => 'baseline_capture',
|
|
'status' => 'running',
|
|
'outcome' => 'pending',
|
|
'summary_counts' => [
|
|
'total' => 10,
|
|
'processed' => 4,
|
|
],
|
|
'context' => [
|
|
'baseline_capture' => [
|
|
'evidence_capture' => [
|
|
'requested' => 10,
|
|
'succeeded' => 3,
|
|
'skipped' => 1,
|
|
],
|
|
'resume_token' => 'resume-123',
|
|
],
|
|
],
|
|
'started_at' => now()->subMinute(),
|
|
]);
|
|
|
|
$component = Livewire::actingAs($user)
|
|
->test(BulkOperationProgress::class)
|
|
->call('refreshRuns');
|
|
|
|
$html = html_entity_decode($component->html(), ENT_QUOTES | ENT_HTML5);
|
|
$pageText = preg_replace('/\s+/', ' ', strip_tags($html));
|
|
|
|
expect($html)->toContain('data-testid="ops-ux-activity-feedback-indeterminate"')
|
|
->and($pageText)->toMatch('/Running · .* · Capturing evidence\./')
|
|
->and($html)->not->toContain('role="progressbar"')
|
|
->and(strip_tags($html))->not->toContain('processed (');
|
|
})->group('ops-ux');
|
|
|
|
it('renders tenant review composite progress from canonical composite metadata without inventing a counted percentage', function (): void {
|
|
[$user, $tenant] = createUserWithTenant(role: 'owner');
|
|
|
|
$this->actingAs($user);
|
|
Filament::setTenant($tenant, true);
|
|
|
|
OperationRun::factory()->create([
|
|
'tenant_id' => (int) $tenant->getKey(),
|
|
'workspace_id' => (int) $tenant->workspace_id,
|
|
'user_id' => (int) $user->getKey(),
|
|
'type' => 'tenant.review.compose',
|
|
'status' => 'running',
|
|
'outcome' => 'pending',
|
|
'context' => [
|
|
'progress' => [
|
|
'composite' => [
|
|
'label' => 'Review composition is aggregating 3 operations.',
|
|
'operation_count' => 3,
|
|
'failed_count' => 0,
|
|
'partial_count' => 0,
|
|
],
|
|
],
|
|
],
|
|
'started_at' => now()->subMinute(),
|
|
]);
|
|
|
|
$component = Livewire::actingAs($user)
|
|
->test(BulkOperationProgress::class)
|
|
->call('refreshRuns');
|
|
|
|
$html = html_entity_decode($component->html(), ENT_QUOTES | ENT_HTML5);
|
|
$pageText = preg_replace('/\s+/', ' ', strip_tags($html));
|
|
|
|
expect($html)->toContain('data-testid="ops-ux-activity-feedback-indeterminate"')
|
|
->and($pageText)->toMatch('/Running · .* · Review composition is aggregating 3 operations\./')
|
|
->and($html)->not->toContain('role="progressbar"')
|
|
->and(strip_tags($html))->not->toContain('processed (');
|
|
})->group('ops-ux');
|
|
|
|
it('renders composite fallback progress without inventing a counted percentage from aggregate counts', function (): void {
|
|
[$user, $tenant] = createUserWithTenant(role: 'owner');
|
|
|
|
$this->actingAs($user);
|
|
Filament::setTenant($tenant, true);
|
|
|
|
OperationRun::factory()->create([
|
|
'tenant_id' => (int) $tenant->getKey(),
|
|
'workspace_id' => (int) $tenant->workspace_id,
|
|
'user_id' => (int) $user->getKey(),
|
|
'type' => 'cross_tenant_promotion.execute',
|
|
'status' => 'running',
|
|
'outcome' => 'pending',
|
|
'summary_counts' => [
|
|
'total' => 10,
|
|
'processed' => 4,
|
|
'operation_count' => 3,
|
|
],
|
|
'started_at' => now()->subMinute(),
|
|
]);
|
|
|
|
$component = Livewire::actingAs($user)
|
|
->test(BulkOperationProgress::class)
|
|
->call('refreshRuns');
|
|
|
|
$html = html_entity_decode($component->html(), ENT_QUOTES | ENT_HTML5);
|
|
$pageText = preg_replace('/\s+/', ' ', strip_tags($html));
|
|
|
|
expect($html)->toContain('data-testid="ops-ux-activity-feedback-indeterminate"')
|
|
->and($pageText)->toMatch('/Running · .* · Composite progress pending\./')
|
|
->and($html)->not->toContain('role="progressbar"')
|
|
->and(strip_tags($html))->not->toContain('processed (');
|
|
})->group('ops-ux');
|
|
|
|
it('renders an indeterminate queued indicator without fake determinate progress', function (): void {
|
|
[$user, $tenant] = createUserWithTenant(role: 'owner');
|
|
|
|
$this->actingAs($user);
|
|
Filament::setTenant($tenant, true);
|
|
|
|
OperationRun::factory()->create([
|
|
'tenant_id' => (int) $tenant->getKey(),
|
|
'workspace_id' => (int) $tenant->workspace_id,
|
|
'user_id' => (int) $user->getKey(),
|
|
'type' => 'inventory_sync',
|
|
'status' => 'queued',
|
|
'outcome' => 'pending',
|
|
'summary_counts' => [
|
|
'processed' => 4,
|
|
],
|
|
'created_at' => now()->subSeconds(15),
|
|
]);
|
|
|
|
$component = Livewire::actingAs($user)
|
|
->test(BulkOperationProgress::class)
|
|
->call('refreshRuns');
|
|
|
|
$html = html_entity_decode($component->html(), ENT_QUOTES | ENT_HTML5);
|
|
$pageText = preg_replace('/\s+/', ' ', strip_tags($html));
|
|
|
|
expect($html)->toContain('data-testid="ops-ux-activity-feedback-indeterminate"')
|
|
->and($html)->toContain('Active operations')
|
|
->and($pageText)->toContain('Queued · now · Waiting for worker.')
|
|
->and($html)->not->toContain('aria-valuenow=')
|
|
->and($html)->toContain('View operation')
|
|
->and($html)->not->toContain('Review operations')
|
|
->and($html)->toContain('Hide activity')
|
|
->and(strip_tags($html))->not->toContain('processed (');
|
|
})->group('ops-ux');
|
|
|
|
it('keeps outcome counters outcome only at the shell host', function (): void {
|
|
[$user, $tenant] = createUserWithTenant(role: 'owner');
|
|
|
|
$this->actingAs($user);
|
|
Filament::setTenant($tenant, true);
|
|
|
|
OperationRun::factory()->create([
|
|
'tenant_id' => (int) $tenant->getKey(),
|
|
'workspace_id' => (int) $tenant->workspace_id,
|
|
'user_id' => (int) $user->getKey(),
|
|
'type' => 'inventory_sync',
|
|
'status' => 'running',
|
|
'outcome' => 'pending',
|
|
'summary_counts' => [
|
|
'succeeded' => 4,
|
|
'failed' => 1,
|
|
'skipped' => 2,
|
|
],
|
|
'started_at' => now()->subMinute(),
|
|
]);
|
|
|
|
$component = Livewire::actingAs($user)
|
|
->test(BulkOperationProgress::class)
|
|
->call('refreshRuns');
|
|
|
|
$html = html_entity_decode($component->html(), ENT_QUOTES | ENT_HTML5);
|
|
$pageText = preg_replace('/\s+/', ' ', strip_tags($html));
|
|
|
|
expect($html)->toContain('data-testid="ops-ux-activity-feedback-indeterminate"')
|
|
->and($pageText)->toMatch('/Running · .* · Progress details pending\./')
|
|
->and($html)->not->toContain('role="progressbar"')
|
|
->and(strip_tags($html))->not->toContain('processed (');
|
|
})->group('ops-ux');
|
|
|
|
it('keeps the queued status pill on one line for the compact banner layout', function (): void {
|
|
[$user, $tenant] = createUserWithTenant(role: 'owner');
|
|
|
|
$this->actingAs($user);
|
|
Filament::setTenant($tenant, true);
|
|
|
|
OperationRun::factory()->create([
|
|
'tenant_id' => (int) $tenant->getKey(),
|
|
'workspace_id' => (int) $tenant->workspace_id,
|
|
'user_id' => (int) $user->getKey(),
|
|
'type' => 'inventory_sync',
|
|
'status' => 'queued',
|
|
'outcome' => 'pending',
|
|
'created_at' => now()->subSeconds(20),
|
|
]);
|
|
|
|
$component = Livewire::actingAs($user)
|
|
->test(BulkOperationProgress::class)
|
|
->call('refreshRuns');
|
|
|
|
$html = $component->html();
|
|
preg_match('/class="([^"]+)"[^>]*data-testid="ops-ux-activity-feedback-status-pill"/m', $html, $matches);
|
|
|
|
expect($matches[1] ?? '')->toContain('whitespace-nowrap')
|
|
->and($html)->toContain('Queued for execution');
|
|
})->group('ops-ux');
|
|
|
|
it('renders the activity banner inside the tenant shell instead of before the application chrome', function (): void {
|
|
[$user, $tenant] = createUserWithTenant(role: 'owner');
|
|
|
|
OperationRun::factory()->create([
|
|
'tenant_id' => (int) $tenant->getKey(),
|
|
'workspace_id' => (int) $tenant->workspace_id,
|
|
'user_id' => (int) $user->getKey(),
|
|
'type' => 'inventory_sync',
|
|
'status' => 'running',
|
|
'outcome' => 'pending',
|
|
'started_at' => now()->subMinute(),
|
|
]);
|
|
|
|
$response = $this->actingAs($user)
|
|
->get(InventoryItemResource::getUrl('index', panel: 'tenant', tenant: $tenant));
|
|
|
|
$response->assertOk();
|
|
|
|
$content = $response->getContent();
|
|
|
|
expect(strpos($content, 'Tenant-Dashboard'))->toBeLessThan(strpos($content, 'Active operations'))
|
|
->and($content)->not->toContain('fixed bottom-4 right-4 z-[999999] w-96 space-y-2');
|
|
})->group('ops-ux');
|
|
|
|
it('registers browser-session collapse affordances and run-enqueued reopen wiring for active hints', function (): void {
|
|
[$user, $tenant] = createUserWithTenant(role: 'owner');
|
|
|
|
$this->actingAs($user);
|
|
Filament::setTenant($tenant, true);
|
|
|
|
OperationRun::factory()->create([
|
|
'tenant_id' => (int) $tenant->getKey(),
|
|
'workspace_id' => (int) $tenant->workspace_id,
|
|
'user_id' => (int) $user->getKey(),
|
|
'type' => 'inventory_sync',
|
|
'status' => 'running',
|
|
'outcome' => 'pending',
|
|
'started_at' => now()->subMinute(),
|
|
]);
|
|
|
|
$component = Livewire::actingAs($user)
|
|
->test(BulkOperationProgress::class)
|
|
->call('refreshRuns');
|
|
|
|
$script = file_get_contents(public_path('js/tenantpilot/ops-ux-progress-widget-poller.js'));
|
|
|
|
expect($component->html())->toContain('data-testid="ops-ux-activity-feedback-toggle"')
|
|
->and($component->html())->toContain('data-testid="ops-ux-activity-feedback-expand"')
|
|
->and($script)->toContain('sessionStorage')
|
|
->and($script)->toContain('ops-ux:run-enqueued');
|
|
})->group('ops-ux'); |