handle($request, function (Request $req): Response { expect($req->query('siteIds'))->toBe(['LDCSER', 'SLELA']); return new Response(); }); // THEN expect($response->getStatusCode())->toBe(200); }); it('normalizes bracket query parameters into array without trailing brackets in key', function (): void { // GIVEN $middleware = new NormalizeQueryStringArrays(); $request = Request::create('/api/v1/employees?siteIds[]=LDCSER&siteIds[]=SLELA', 'GET'); // WHEN $response = $middleware->handle($request, function (Request $req): Response { expect($req->query('siteIds'))->toBe(['LDCSER', 'SLELA']); return new Response(); }); // THEN expect($response->getStatusCode())->toBe(200); }); it('preserves and normalizes nested bracket parameters into multidimensional array', function (): void { // GIVEN $middleware = new NormalizeQueryStringArrays(); $request = Request::create('/api/v1/employees?filter[date][from]=2024-01-01&filter[date][to]=2024-01-02', 'GET'); // WHEN $response = $middleware->handle($request, function (Request $req): Response { expect($req->query('filter'))->toBe([ 'date' => [ 'from' => '2024-01-01', 'to' => '2024-01-02', ], ]); return new Response(); }); // THEN expect($response->getStatusCode())->toBe(200); }); it('preserves dots in query parameter keys without converting to underscores', function (): void { // GIVEN $middleware = new NormalizeQueryStringArrays(); $request = Request::create('/api/v1/employees?filter.status=active', 'GET'); // WHEN $response = $middleware->handle($request, function (Request $req): Response { expect($req->query('filter.status'))->toBe('active'); return new Response(); }); // THEN expect($response->getStatusCode())->toBe(200); }); it('preserves percent-encoded values without double decoding', function (): void { // GIVEN $middleware = new NormalizeQueryStringArrays(); $encodedVal = urlencode('%9999999%'); $request = Request::create("/api/v1/inco-sheets/search?incoIdLike={$encodedVal}", 'GET'); // WHEN $response = $middleware->handle($request, function (Request $req): Response { expect($req->query('incoIdLike'))->toBe('%9999999%'); return new Response(); }); // THEN expect($response->getStatusCode())->toBe(200); }); it('handles empty query string gracefully', function (): void { // GIVEN $middleware = new NormalizeQueryStringArrays(); $request = Request::create('/api/v1/employees', 'GET'); // WHEN $response = $middleware->handle($request, function (Request $req): Response { expect($req->query->all())->toBeEmpty(); return new Response(); }); // THEN expect($response->getStatusCode())->toBe(200); }); it('bypasses non-v1 routes and preserves native PHP query behavior', function (): void { // GIVEN $middleware = new NormalizeQueryStringArrays(); $request = Request::create('/ping?siteIds=LDCSER&siteIds=SLELA', 'GET'); // WHEN $response = $middleware->handle($request, function (Request $req): Response { // Native PHP behavior: last value wins if not normalized expect($req->query('siteIds'))->toBe('SLELA'); return new Response(); }); // THEN expect($response->getStatusCode())->toBe(200); }); });