You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

355 lines
13 KiB

3 months ago
<?php
namespace Tests\Feature;
use App\Models\AdminUser;
use App\Models\Application;
4 weeks ago
use App\Models\ApplicationFile;
use App\Models\ApplicationReviewScore;
3 months ago
use App\Models\Competition;
4 weeks ago
use App\Models\FormSchemaDefinition;
use App\Models\Reviewer;
4 weeks ago
use App\Models\ReviewerScope;
3 months ago
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Laravel\Sanctum\Sanctum;
use Tests\TestCase;
class AdminApplicationListTest extends TestCase
{
use RefreshDatabase;
public function test_admin_application_list_excludes_soft_deleted_records(): void
{
Sanctum::actingAs(AdminUser::query()->create([
'username' => 'admin_list',
'password_hash' => 'unused',
'name' => '管理员',
'status' => 'active',
]));
$competition = Competition::query()->create([
'slug' => 'xxf',
'name' => '测试赛',
'published' => true,
]);
$active = Application::query()->create([
'user_id' => User::query()->create(['mobile' => '13800138001'])->id,
'competition_id' => $competition->id,
'status' => 'submitted',
'project_name' => '有效项目',
]);
$deleted = Application::query()->create([
'user_id' => User::query()->create(['mobile' => '13800138002'])->id,
'competition_id' => $competition->id,
'status' => 'submitted',
'project_name' => '已删除项目',
]);
$deleted->forceFill(['deleted_at' => now()])->save();
$response = $this->getJson("/api/v1/admin/competitions/{$competition->id}/applications?status=submitted")
->assertOk();
$ids = collect($response->json('data'))->pluck('id')->all();
$this->assertContains($active->id, $ids);
$this->assertNotContains($deleted->id, $ids);
}
3 months ago
public function test_admin_application_list_filters_by_review_result(): void
{
Sanctum::actingAs(AdminUser::query()->create([
'username' => 'admin_filter',
'password_hash' => 'unused',
'name' => '管理员',
'status' => 'active',
]));
$competition = Competition::query()->create([
'slug' => 'xxf-filter',
'name' => '筛选测试赛',
'published' => true,
]);
$passed = Application::query()->create([
'user_id' => User::query()->create(['mobile' => '13800138011'])->id,
'competition_id' => $competition->id,
'status' => 'submitted',
'project_name' => '已通过项目',
'review_result' => 'passed',
]);
Application::query()->create([
'user_id' => User::query()->create(['mobile' => '13800138012'])->id,
'competition_id' => $competition->id,
'status' => 'submitted',
'project_name' => '待评定项目',
'review_result' => null,
]);
$response = $this->getJson("/api/v1/admin/competitions/{$competition->id}/applications?status=submitted&review_result=passed")
->assertOk();
$ids = collect($response->json('data'))->pluck('id')->all();
$this->assertContains($passed->id, $ids);
$this->assertCount(1, $ids);
}
4 weeks ago
public function test_admin_application_list_survives_schema_without_list_flag(): void
{
Sanctum::actingAs(AdminUser::query()->create([
'username' => 'admin_schema_list',
'password_hash' => 'unused',
'name' => '管理员',
'status' => 'active',
]));
$competition = Competition::query()->create([
'slug' => 'xxf-schema-list',
'name' => '缺 list 字段赛',
'published' => true,
]);
$schema = FormSchemaDefinition::query()->create([
'competition_id' => $competition->id,
'purpose' => FormSchemaDefinition::PURPOSE_SIGNUP,
'name' => '报名表',
'version' => 1,
'is_published' => true,
'schema_json' => [
[
'key' => 'contact_email',
'type' => 'email',
'label' => '邮箱',
],
[
'key' => 'event_location',
'type' => 'select',
'label' => '意向参赛地点',
],
],
]);
$competition->forceFill(['form_schema_id' => $schema->id])->save();
Application::query()->create([
'user_id' => User::query()->create(['mobile' => '13800138021'])->id,
'competition_id' => $competition->id,
'status' => 'submitted',
'project_name' => '缺 list 项目',
'review_eligible' => true,
]);
$this->getJson("/api/v1/admin/competitions/{$competition->id}/applications?page=1&per_page=15&status=submitted&review_eligible=true")
->assertOk()
->assertJsonPath('data.0.project_name', '缺 list 项目');
}
public function test_admin_application_list_keeps_files_count_when_sorting_by_team_avg(): void
{
Sanctum::actingAs(AdminUser::query()->create([
'username' => 'admin_files_count',
'password_hash' => 'unused',
'name' => '管理员',
'status' => 'active',
]));
$competition = Competition::query()->create([
'slug' => 'xxf-files-count',
'name' => '附件计数赛',
'published' => true,
]);
$application = Application::query()->create([
'user_id' => User::query()->create(['mobile' => '13800138031'])->id,
'competition_id' => $competition->id,
'status' => 'submitted',
'project_name' => '有附件项目',
]);
ApplicationFile::query()->create([
'application_id' => $application->id,
'kind' => 'plan',
'disk' => 'public',
'path' => 'applications/plan.pdf',
'original_name' => '商业计划书.pdf',
'size' => 1024,
'mime' => 'application/pdf',
]);
ApplicationFile::query()->create([
'application_id' => $application->id,
'kind' => 'supporting',
'disk' => 'public',
'path' => 'applications/extra.pdf',
'original_name' => '补充材料.pdf',
'size' => 2048,
'mime' => 'application/pdf',
]);
$this->getJson("/api/v1/admin/competitions/{$competition->id}/applications?status=submitted&sort_by=team_avg&sort_dir=desc")
->assertOk()
->assertJsonPath('data.0.id', $application->id)
->assertJsonPath('data.0.files_count', 2);
}
public function test_admin_application_list_rounds_team_avg_to_two_decimals(): void
{
Sanctum::actingAs(AdminUser::query()->create([
'username' => 'admin_avg_round',
'password_hash' => 'unused',
'name' => '管理员',
'status' => 'active',
]));
$competition = Competition::query()->create([
'slug' => 'xxf-avg-round',
'name' => '均分取整赛',
'published' => true,
]);
$application = Application::query()->create([
'user_id' => User::query()->create(['mobile' => '13800138032'])->id,
'competition_id' => $competition->id,
'status' => 'submitted',
'project_name' => '小数均分项目',
]);
$reviewerA = Reviewer::query()->create([
'mobile' => '13900139201',
'username' => 'rev_avg_a',
'name' => '评委A',
'status' => 'active',
'password_hash' => 'unused',
]);
$reviewerB = Reviewer::query()->create([
'mobile' => '13900139202',
'username' => 'rev_avg_b',
'name' => '评委B',
'status' => 'active',
'password_hash' => 'unused',
]);
ApplicationReviewScore::query()->create([
'application_id' => $application->id,
'reviewer_id' => $reviewerA->id,
'payload_json' => ['line_total' => 80.33],
'line_total' => 80.33,
]);
ApplicationReviewScore::query()->create([
'application_id' => $application->id,
'reviewer_id' => $reviewerB->id,
'payload_json' => ['line_total' => 80.34],
'line_total' => 80.34,
]);
$this->getJson("/api/v1/admin/competitions/{$competition->id}/applications?status=submitted")
->assertOk()
->assertJsonPath('data.0.id', $application->id)
->assertJsonPath('data.0.team_sum', 160.67)
->assertJsonPath('data.0.team_avg', 80.34);
}
4 weeks ago
public function test_review_progress_counts_region_reviewers_not_track_rows(): void
{
Sanctum::actingAs(AdminUser::query()->create([
'username' => 'admin_progress_region',
'password_hash' => 'unused',
'name' => '管理员',
'status' => 'active',
]));
$competition = Competition::query()->create([
'slug' => 'hsxt-progress',
'name' => '赛区进程赛',
'published' => true,
]);
$suzhouA = Reviewer::query()->create([
'mobile' => '13900139301',
'username' => 'suzhou_a',
'name' => '苏州甲',
'status' => 'active',
'password_hash' => 'unused',
]);
$suzhouB = Reviewer::query()->create([
'mobile' => '13900139302',
'username' => 'suzhou_b',
'name' => '苏州乙',
'status' => 'active',
'password_hash' => 'unused',
]);
$shanghai = Reviewer::query()->create([
'mobile' => '13900139303',
'username' => 'shanghai_a',
'name' => '上海甲',
'status' => 'active',
'password_hash' => 'unused',
]);
foreach (['guang_xinpian', 'other'] as $track) {
ReviewerScope::query()->create([
'competition_id' => $competition->id,
'reviewer_id' => $suzhouB->id,
'track_code' => $track,
'event_location' => 'suzhou',
]);
ReviewerScope::query()->create([
'competition_id' => $competition->id,
'reviewer_id' => $shanghai->id,
'track_code' => $track,
'event_location' => 'shanghai',
]);
}
ReviewerScope::query()->create([
'competition_id' => $competition->id,
'reviewer_id' => $suzhouA->id,
'track_code' => 'guang_xinpian',
'event_location' => 'suzhou',
]);
$twoReviewers = Application::query()->create([
'user_id' => User::query()->create(['mobile' => '13800138301'])->id,
'competition_id' => $competition->id,
'status' => 'submitted',
'project_name' => '双评委苏州项目',
'track' => 'other',
'event_location' => 'suzhou',
'review_eligible' => true,
]);
ApplicationReviewScore::query()->create([
'application_id' => $twoReviewers->id,
'reviewer_id' => $suzhouA->id,
'payload_json' => ['line_total' => 85.43],
'line_total' => 85.43,
]);
$oneReviewer = Application::query()->create([
'user_id' => User::query()->create(['mobile' => '13800138302'])->id,
'competition_id' => $competition->id,
'status' => 'submitted',
'project_name' => '单评委苏州项目',
'track' => 'other',
'event_location' => 'suzhou',
'review_eligible' => true,
]);
$first = collect($this->getJson("/api/v1/admin/competitions/{$competition->id}/applications?status=submitted&review_eligible=true")
->assertOk()
->json('data'))->keyBy('id');
$this->assertSame('1/2', $first[$twoReviewers->id]['review_progress']);
$this->assertFalse($first[$twoReviewers->id]['review_fully_completed']);
$this->assertSame(85.43, $first[$twoReviewers->id]['team_sum']);
ReviewerScope::query()->where('reviewer_id', $suzhouB->id)->delete();
ApplicationReviewScore::query()->create([
'application_id' => $oneReviewer->id,
'reviewer_id' => $suzhouA->id,
'payload_json' => ['line_total' => 90],
'line_total' => 90,
]);
$second = collect($this->getJson("/api/v1/admin/competitions/{$competition->id}/applications?status=submitted&review_eligible=true")
->assertOk()
->json('data'))->keyBy('id');
$this->assertSame('1/1', $second[$oneReviewer->id]['review_progress']);
$this->assertTrue($second[$oneReviewer->id]['review_fully_completed']);
$this->assertSame(90, $second[$oneReviewer->id]['team_sum']);
}
3 months ago
}