diff --git a/app/tests/Feature/Http/Webhook/SupplierWebhookValidationFormatTest.php b/app/tests/Feature/Http/Webhook/SupplierWebhookValidationFormatTest.php new file mode 100644 index 00000000..a2486934 --- /dev/null +++ b/app/tests/Feature/Http/Webhook/SupplierWebhookValidationFormatTest.php @@ -0,0 +1,65 @@ +where('key', 'supplier_webhook_secret') + ->update(['value' => 'test-secret-32chars-aaaaaaaaaaaaaa']); + SystemSetting::query() + ->where('key', 'supplier_ip_allowlist') + ->update(['value' => '[]']); +}); + +it('returns 422 JSON when supplier posts invalid payload WITHOUT Accept: application/json header', function () { + // Воспроизводит реальное поведение crm.bp-gr.ru: POST без Accept-JSON. + // До фикса (302→422) Laravel редиректил на / с Set-Cookie, поставщик + // терял тело запроса. После фикса всегда JSON. + $response = $this->call( + 'POST', + '/api/webhook/supplier/test-secret-32chars-aaaaaaaaaaaaaa', + [], // params + [], // cookies + [], // files + ['HTTP_CONTENT_TYPE' => 'application/x-www-form-urlencoded'], // server: НЕТ Accept JSON + http_build_query([ + 'vid' => 1, + 'project' => 'invalid_no_b_prefix', + 'phone' => '79991234567', + 'time' => time(), + ]) + ); + + $response->assertStatus(422); + expect($response->headers->get('Content-Type'))->toContain('application/json'); + $response->assertJsonStructure(['message', 'errors' => ['project']]); +}); + +it('still works correctly for postJson clients (regression)', function () { + $response = $this->postJson('/api/webhook/supplier/test-secret-32chars-aaaaaaaaaaaaaa', [ + 'vid' => 1, + 'project' => 'invalid_no_b_prefix', + 'phone' => '79991234567', + 'time' => time(), + ]); + + $response->assertStatus(422)->assertJsonValidationErrors('project'); +}); + +it('non-webhook routes still use default render (no JSON forced)', function () { + // Регрессионный тест: дефолтный render остальных routes не сломан + // (например /login — должен возвращать redirect, а не JSON). + $response = $this->call( + 'POST', + '/login', + ['email' => 'bad', 'password' => ''], + [], [], [], + ); + // Любой не-200 кроме 422-JSON допустим — главное чтобы наш fix не перехватил + expect($response->headers->get('Content-Type'))->not->toContain('application/json'); +});