pp-planer/tests/Feature/CtsApiSpikeTest.php
Thorsten Bus d99ca1e017 chore: verify CTS API token auth and package compatibility
- Install 5pm-hdh/churchtools-api v2.1.0
- Verify CTConfig::setApiKey() and authWithLoginToken() both available
- Document API response shapes for /api/events and /api/songs
- Confirm CCLI field present, lyrics available, arrangements included
- TDD: CtsApiSpikeTest with 2 tests, 11 assertions - all passing
- Evidence saved to .sisyphus/evidence/task-0-*.txt
- Findings documented in docs/api-response-shapes.md

Related: Task 0 (Wave 0 - API Spike)
2026-03-01 18:56:03 +01:00

120 lines
3.6 KiB
PHP

<?php
use CTApi\CTClient;
use CTApi\CTConfig;
use GuzzleHttp\Psr7\Response;
use Psr\Http\Message\ResponseInterface;
it('syncs mocked future events and song shape through the CTS pipeline', function () {
$eventsPayload = [
'data' => [
[
'domainIdentifier' => '100',
'title' => 'Gottesdienst Sonntag',
'startDate' => '2026-03-08T10:00:00+00:00',
'note' => 'Probe',
],
],
'meta' => [
'pagination' => [
'lastPage' => 1,
],
],
];
$songPayload = [
'data' => [
'songId' => '1',
'name' => 'Way Maker',
'ccli' => '7115744',
'arrangements' => [
['id' => '11', 'name' => 'Normal', 'isDefault' => true],
],
'lyrics' => [
'type' => 'text',
'cclid' => '7115744',
'lyricParts' => [
['key' => 'v1', 'text' => "Du bist hier"],
],
],
],
];
$mockClient = new CtsApiSpikeMockClient([
'/api/events' => [new Response(200, [], json_encode($eventsPayload, JSON_THROW_ON_ERROR))],
'/api/songs/1' => [new Response(200, [], json_encode($songPayload, JSON_THROW_ON_ERROR))],
]);
$result = \App\Cts\CtsApiSpikeSync::run(
apiUrl: 'https://example.church.tools',
apiToken: 'token-abc',
fromDate: '2026-03-01',
songId: 1,
client: $mockClient,
);
expect($result['events']['count'])->toBe(1)
->and($result['events']['first']['title'])->toBe('Gottesdienst Sonntag')
->and($result['song']['hasCcli'])->toBeTrue()
->and($result['song']['hasLyrics'])->toBeTrue()
->and($result['song']['arrangements_count'])->toBe(1)
->and($result['auth']['method'])->toBe('setApiKey');
$eventsCall = $mockClient->firstCallFor('GET', '/api/events');
expect($eventsCall['options']['query']['from'])->toBe('2026-03-01')
->and($eventsCall['options']['query']['page'])->toBe(1)
->and(CTConfig::getRequestConfig()['query']['login_token'])->toBe('token-abc');
});
it('returns auth blocker when API token is missing', function () {
$result = \App\Cts\CtsApiSpikeSync::run(
apiUrl: 'https://example.church.tools',
apiToken: '',
fromDate: '2026-03-01',
songId: 1,
client: new CtsApiSpikeMockClient([]),
);
expect($result['auth']['ok'])->toBeFalse()
->and($result['auth']['blocker'])->toContain('CTS_API_TOKEN');
});
final class CtsApiSpikeMockClient extends CTClient
{
private array $responsesByUri;
private array $calls = [];
public function __construct(array $responsesByUri)
{
$this->responsesByUri = $responsesByUri;
}
public function get($uri, array $options = []): ResponseInterface
{
$this->calls[] = [
'method' => 'GET',
'uri' => $uri,
'options' => $options,
];
if (! isset($this->responsesByUri[$uri]) || $this->responsesByUri[$uri] === []) {
return new Response(404, [], json_encode(['data' => []], JSON_THROW_ON_ERROR));
}
return array_shift($this->responsesByUri[$uri]);
}
public function firstCallFor(string $method, string $uri): array
{
foreach ($this->calls as $call) {
if ($call['method'] === $method && $call['uri'] === $uri) {
return $call;
}
}
throw new RuntimeException("No call recorded for {$method} {$uri}");
}
}