create(); $user = User::factory()->create(['tenant_id' => $tenant->id]); $campaign = AdCampaign::create([ 'tenant_id' => $tenant->id, 'name' => 'C', 'audience_days' => 10, 'use_uploaded_list' => false, ]); return [$tenant, $user, $campaign]; } it('клиент видит ленту своей кампании по порядку', function () { [$tenant, $user, $campaign] = messageEndpointCampaign(); AdCampaignMessage::create([ 'tenant_id' => $tenant->id, 'campaign_id' => $campaign->id, 'author' => AdCampaignMessage::AUTHOR_YANDEX, 'body' => 'Первое', ]); AdCampaignMessage::create([ 'tenant_id' => $tenant->id, 'campaign_id' => $campaign->id, 'author' => AdCampaignMessage::AUTHOR_CLIENT, 'body' => 'Второе', ]); $res = $this->actingAs($user)->getJson("/api/advertising/campaigns/{$campaign->id}/messages"); $res->assertOk(); expect($res->json('messages.0.body'))->toBe('Первое') ->and($res->json('messages.0.author'))->toBe(AdCampaignMessage::AUTHOR_YANDEX) ->and($res->json('messages.1.body'))->toBe('Второе'); }); /** * Наценка — наша кухня, клиенту её видеть нельзя нигде, включая переписку. * Ручка отдаёт строго перечисленные поля сообщения, и так должно остаться. */ it('в ленте нет ни наценки, ни закупочной цены', function () { [$tenant, $user, $campaign] = messageEndpointCampaign(); AdCampaignMessage::create([ 'tenant_id' => $tenant->id, 'campaign_id' => $campaign->id, 'author' => AdCampaignMessage::AUTHOR_YANDEX, 'body' => 'Изображение не подошло', ]); $res = $this->actingAs($user)->getJson("/api/advertising/campaigns/{$campaign->id}/messages"); $res->assertOk(); expect($res->getContent())->not->toContain('yandex_cost_rub') ->and($res->getContent())->not->toContain('ad_margin_percent') ->and(array_keys($res->json('messages.0')))->toBe([ 'id', 'author', 'banner_id', 'body', 'file_name', 'file_size', 'created_at', ]); }); /** Чужая переписка — чужие бумаги и чужие претензии модератора. */ it('чужую ленту клиент не видит', function () { [$tenantA, , $campaignA] = messageEndpointCampaign(); AdCampaignMessage::create([ 'tenant_id' => $tenantA->id, 'campaign_id' => $campaignA->id, 'author' => AdCampaignMessage::AUTHOR_YANDEX, 'body' => 'Чужое', ]); [, $userB] = messageEndpointCampaign(); $res = $this->actingAs($userB)->getJson("/api/advertising/campaigns/{$campaignA->id}/messages"); $res->assertStatus(404); expect($res->getContent())->not->toContain('Чужое'); }); it('без входа лента не отдаётся', function () { [, , $campaign] = messageEndpointCampaign(); $this->getJson("/api/advertising/campaigns/{$campaign->id}/messages")->assertStatus(401); }); it('клиент отправляет ответ с документом', function () { Storage::fake('local'); [, $user, $campaign] = messageEndpointCampaign(); $res = $this->actingAs($user)->postJson("/api/advertising/campaigns/{$campaign->id}/messages", [ 'body' => 'Прикладываю свидетельство', 'file' => UploadedFile::fake()->create('svidetelstvo.pdf', 200, 'application/pdf'), ]); $res->assertStatus(201); $message = AdCampaignMessage::where('campaign_id', $campaign->id)->first(); expect($message->author)->toBe(AdCampaignMessage::AUTHOR_CLIENT) ->and($message->body)->toBe('Прикладываю свидетельство') ->and($message->file_name)->toBe('svidetelstvo.pdf') ->and($message->file_path)->not->toBeNull(); Storage::disk('local')->assertExists($message->file_path); }); it('ответ без текста и без файла не принимается', function () { Storage::fake('local'); [, $user, $campaign] = messageEndpointCampaign(); $this->actingAs($user) ->postJson("/api/advertising/campaigns/{$campaign->id}/messages", []) ->assertStatus(422); expect(AdCampaignMessage::where('campaign_id', $campaign->id)->count())->toBe(0); }); /** * Приложение исполняемого файла — не «неудобство», а дыра: файл ляжет на диск боевого * сервера, и дальше вопрос только в том, кто его оттуда позовёт. */ it('файл не того типа отклоняется и на диск не ложится', function () { Storage::fake('local'); [, $user, $campaign] = messageEndpointCampaign(); $res = $this->actingAs($user)->postJson("/api/advertising/campaigns/{$campaign->id}/messages", [ 'body' => 'вот', 'file' => UploadedFile::fake()->create('opasno.exe', 10, 'application/octet-stream'), ]); $res->assertStatus(422); $res->assertJsonValidationErrors('file'); expect(AdCampaignMessage::where('campaign_id', $campaign->id)->count())->toBe(0) ->and(Storage::disk('local')->allFiles())->toBe([]); }); it('файл тяжелее предела отклоняется', function () { Storage::fake('local'); [, $user, $campaign] = messageEndpointCampaign(); $res = $this->actingAs($user)->postJson("/api/advertising/campaigns/{$campaign->id}/messages", [ 'file' => UploadedFile::fake()->create('big.pdf', 10241, 'application/pdf'), ]); $res->assertStatus(422); expect(AdCampaignMessage::where('campaign_id', $campaign->id)->count())->toBe(0) ->and(Storage::disk('local')->allFiles())->toBe([]); }); it('в чужую кампанию написать нельзя', function () { Storage::fake('local'); [, , $campaignA] = messageEndpointCampaign(); [, $userB] = messageEndpointCampaign(); $this->actingAs($userB) ->postJson("/api/advertising/campaigns/{$campaignA->id}/messages", ['body' => 'привет']) ->assertStatus(404); expect(AdCampaignMessage::where('campaign_id', $campaignA->id)->count())->toBe(0); }); it('свой файл клиент скачивает, чужой — нет', function () { Storage::fake('local'); [, $user, $campaign] = messageEndpointCampaign(); $this->actingAs($user)->postJson("/api/advertising/campaigns/{$campaign->id}/messages", [ 'file' => UploadedFile::fake()->create('doc.pdf', 100, 'application/pdf'), ])->assertStatus(201); $message = AdCampaignMessage::where('campaign_id', $campaign->id)->first(); $this->actingAs($user) ->get("/api/advertising/campaigns/{$campaign->id}/messages/{$message->id}/file") ->assertOk(); [, $userB] = messageEndpointCampaign(); $this->actingAs($userB) ->get("/api/advertising/campaigns/{$campaign->id}/messages/{$message->id}/file") ->assertStatus(404); });