Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 40 additions & 1 deletion generators/php/sdk/src/wire-tests/WireTestSetupGenerator.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { File } from "@fern-api/base-generator";
import { RelativeFilePath } from "@fern-api/fs-utils";
import { WireMock } from "@fern-api/mock-utils";
import { WireMock, WireMockStubMapping } from "@fern-api/mock-utils";
import { FernIr } from "@fern-fern/ir-sdk";
import { SdkGeneratorContext } from "../SdkGeneratorContext.js";

Expand Down Expand Up @@ -33,8 +33,47 @@ export class WireTestSetupGenerator {
return new WireMock().convertToWireMock(ir);
}

/**
* ISO 8601 datetime pattern that matches values with `.000` milliseconds.
* Example: "2008-01-02T00:00:00.000Z" or "2008-01-02T00:00:00.000+05:00"
*/
private static readonly DATETIME_WITH_ZERO_MILLIS_REGEX =
/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.000(Z|[+-]\d{2}:\d{2})$/;

/**
* Strips ".000" milliseconds from all datetime query parameter values in WireMock stub mappings.
* PHP's DateTimeInterface::RFC3339 format does not include fractional seconds, so the SDK
* serializes datetimes as e.g. "2022-01-02T00:00:00Z" while mock-utils generates
* "2022-01-02T00:00:00.000Z" (via Date.toISOString()). Since WireMock's equalTo matcher
* is exact-match, the stubs never fire unless we strip the zero milliseconds.
*
* Mutates the input in-place for efficiency.
*/
private static stripDatetimeMilliseconds(stubMapping: WireMockStubMapping): void {
for (const mapping of stubMapping.mappings) {
if (mapping.request.queryParameters) {
for (const [, value] of Object.entries(mapping.request.queryParameters)) {
const paramValue = value as { equalTo: string };
if (
paramValue.equalTo != null &&
WireTestSetupGenerator.DATETIME_WITH_ZERO_MILLIS_REGEX.test(paramValue.equalTo)
) {
paramValue.equalTo = paramValue.equalTo.replace(".000", "");
}
}
}
}
}

private generateWireMockConfigFile(): void {
const wireMockConfigContent = WireTestSetupGenerator.getWiremockConfigContent(this.ir);

// mock-utils generates datetime values using Date.toISOString() which always includes
// ".000Z" milliseconds. PHP's DateTimeInterface::RFC3339 format omits fractional seconds,
// so the SDK sends e.g. "2022-01-02T00:00:00Z". Strip the zero milliseconds from WireMock
// stubs so that equalTo exact-matching works correctly.
WireTestSetupGenerator.stripDatetimeMilliseconds(wireMockConfigContent);

this.context.project.addRawFiles(
new File(
"wiremock-mappings.json",
Expand Down
13 changes: 13 additions & 0 deletions generators/php/sdk/versions.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,17 @@
# yaml-language-server: $schema=../../../fern-versions-yml.schema.json
- version: 2.1.12
changelogEntry:
- summary: |
Fix WireMock datetime mismatch in wire tests. The mock-utils package generates datetime
query parameter values with milliseconds (e.g., `2022-01-02T00:00:00.000Z`) via
`Date.toISOString()`, but PHP's `DateTimeInterface::RFC3339` format omits fractional
seconds (e.g., `2022-01-02T00:00:00Z`). Since WireMock's `equalTo` is an exact-match,
the stubs never fired. Now strips zero milliseconds from WireMock datetime query
parameter values to match the PHP SDK's serialization format.
type: fix
createdAt: "2026-03-12"
irVersion: 62

- version: 2.1.11
changelogEntry:
- summary: |
Expand Down
Loading