128 lines
5.3 KiB
PHP
128 lines
5.3 KiB
PHP
|
|
<?php
|
|||
|
|
|
|||
|
|
declare(strict_types=1);
|
|||
|
|
|
|||
|
|
use App\Services\Sms\Providers\MtsSmsProvider;
|
|||
|
|
use App\Services\Sms\SmsDeliveryState;
|
|||
|
|
use App\Services\Sms\SmsSendException;
|
|||
|
|
use Illuminate\Support\Facades\Http;
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* Строка листа 5.1: по каждому номеру видна настоящая судьба.
|
|||
|
|
*
|
|||
|
|
* 🔴 Форма ответа взята из ЖИВОЙ пробы 30.07 (журнал В-211), а НЕ из документации
|
|||
|
|
* МТС: там описан вход по логину-паролю (`events_info` с `message_id`/`event_at`),
|
|||
|
|
* а мы ходим по токену и получаем `data[].statuses[]`. Тест на выдуманной форме
|
|||
|
|
* охранял бы выдумку (урок В-72: записанный чужой вывод — гипотеза, не факт).
|
|||
|
|
*
|
|||
|
|
* Помощники с префиксом mtsDelivery* — имена функций в Pest ГЛОБАЛЬНЫЕ.
|
|||
|
|
* Телефоны только синтетические 7999… — реальные НИКОГДА.
|
|||
|
|
*/
|
|||
|
|
function mtsDeliveryProvider(): MtsSmsProvider
|
|||
|
|
{
|
|||
|
|
return new MtsSmsProvider('токен', ['mts'], ['*' => 300], 'https://api.mts.test/v1');
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* Ответ МТС на вопрос о судьбе — ровно той формы, что пришла живьём.
|
|||
|
|
*
|
|||
|
|
* @param array<int, array<string, mixed>> $statuses
|
|||
|
|
* @return array<string, mixed>
|
|||
|
|
*/
|
|||
|
|
function mtsDeliveryBody(string $messageId, array $statuses): array
|
|||
|
|
{
|
|||
|
|
return ['code' => 0, 'data' => [['messageID' => $messageId, 'statuses' => $statuses]]];
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
it('читает доставленное сообщение по живой форме ответа', function () {
|
|||
|
|
Http::fake(['*' => Http::response(mtsDeliveryBody('44747238', [[
|
|||
|
|
'msid' => '79990000001',
|
|||
|
|
'status' => 'Delivered',
|
|||
|
|
'date' => '2026-07-30T16:31:02',
|
|||
|
|
'userDeliveryDate' => '2026-07-30T16:31:40',
|
|||
|
|
'partCount' => 2,
|
|||
|
|
'isViber' => false,
|
|||
|
|
'trafficPatternType' => 'service',
|
|||
|
|
'cost' => 3.4,
|
|||
|
|
]]))]);
|
|||
|
|
|
|||
|
|
$reports = mtsDeliveryProvider()->fetchDelivery(['44747238']);
|
|||
|
|
|
|||
|
|
expect($reports)->toHaveCount(1);
|
|||
|
|
expect($reports[0]->providerMessageId)->toBe('44747238');
|
|||
|
|
expect($reports[0]->phone)->toBe('79990000001');
|
|||
|
|
expect($reports[0]->state)->toBe(SmsDeliveryState::DELIVERED);
|
|||
|
|
expect($reports[0]->deliveredAt?->toDateTimeString())->toBe('2026-07-30 16:31:40');
|
|||
|
|
expect($reports[0]->partCount)->toBe(2);
|
|||
|
|
expect($reports[0]->providerCost)->toBe('3.4');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
it('читает «принял, но не отправил» — тот самый случай живой пробы 30.07', function () {
|
|||
|
|
Http::fake(['*' => Http::response(mtsDeliveryBody('44747239', [[
|
|||
|
|
'msid' => '79990000002',
|
|||
|
|
'status' => 'NotSent',
|
|||
|
|
'date' => '2026-07-30T16:31:02',
|
|||
|
|
'userDeliveryDate' => null,
|
|||
|
|
'partCount' => 1,
|
|||
|
|
'cost' => 0,
|
|||
|
|
]]))]);
|
|||
|
|
|
|||
|
|
$reports = mtsDeliveryProvider()->fetchDelivery(['44747239']);
|
|||
|
|
|
|||
|
|
expect($reports[0]->state)->toBe(SmsDeliveryState::NOT_SENT);
|
|||
|
|
expect($reports[0]->deliveredAt)->toBeNull();
|
|||
|
|
expect($reports[0]->providerCost)->toBe('0');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
it('читает «везу» и «не довёз» как разные судьбы', function () {
|
|||
|
|
Http::fake(['*' => Http::response(['code' => 0, 'data' => [
|
|||
|
|
['messageID' => '1', 'statuses' => [['msid' => '79990000003', 'status' => 'Sending']]],
|
|||
|
|
['messageID' => '2', 'statuses' => [['msid' => '79990000004', 'status' => 'NotDelivered']]],
|
|||
|
|
]])]);
|
|||
|
|
|
|||
|
|
$reports = mtsDeliveryProvider()->fetchDelivery(['1', '2']);
|
|||
|
|
|
|||
|
|
expect($reports[0]->state)->toBe(SmsDeliveryState::SENDING);
|
|||
|
|
expect($reports[1]->state)->toBe(SmsDeliveryState::NOT_DELIVERED);
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
it('незнакомое слово оператора не угадывает, а отдаёт пустую судьбу и само слово', function () {
|
|||
|
|
Http::fake(['*' => Http::response(mtsDeliveryBody('1', [[
|
|||
|
|
'msid' => '79990000005',
|
|||
|
|
'status' => 'СовершенноНовоеСлово',
|
|||
|
|
'partCount' => 1,
|
|||
|
|
]]))]);
|
|||
|
|
|
|||
|
|
$reports = mtsDeliveryProvider()->fetchDelivery(['1']);
|
|||
|
|
|
|||
|
|
expect($reports[0]->state)->toBeNull();
|
|||
|
|
expect($reports[0]->rawState)->toBe('СовершенноНовоеСлово');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
it('спрашивает номера сообщений одной строкой через запятую', function () {
|
|||
|
|
Http::fake(['*' => Http::response(['code' => 0, 'data' => []])]);
|
|||
|
|
|
|||
|
|
mtsDeliveryProvider()->fetchDelivery(['1', '2', '3']);
|
|||
|
|
|
|||
|
|
Http::assertSent(fn ($request) => str_contains(urldecode($request->url()), 'messageIDs=1,2,3'));
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
it('пустой список никого не спрашивает вовсе', function () {
|
|||
|
|
Http::fake(['*' => Http::response(['code' => 0, 'data' => []])]);
|
|||
|
|
|
|||
|
|
expect(mtsDeliveryProvider()->fetchDelivery([]))->toBe([]);
|
|||
|
|
|
|||
|
|
Http::assertNothingSent();
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
it('отказ МТС — не окончательный: судьбу всегда можно переспросить позже', function () {
|
|||
|
|
Http::fake(['*' => Http::response('', 502)]);
|
|||
|
|
|
|||
|
|
try {
|
|||
|
|
mtsDeliveryProvider()->fetchDelivery(['1']);
|
|||
|
|
$this->fail('ожидали отказ канала');
|
|||
|
|
} catch (SmsSendException $e) {
|
|||
|
|
expect($e->terminal)->toBeFalse();
|
|||
|
|
}
|
|||
|
|
});
|