From 2d1e736c76b03b946c4e475d252fb7d08706964e Mon Sep 17 00:00:00 2001 From: iscai-msft Date: Fri, 23 Jan 2026 15:42:42 -0500 Subject: [PATCH 1/5] add specs --- packages/http-specs/spec-summary.md | 49 ++++++++ .../specs/payload/pageable/main.tsp | 76 ++++++++++++ .../specs/payload/pageable/mockapi.ts | 109 ++++++++++++++++++ 3 files changed, 234 insertions(+) diff --git a/packages/http-specs/spec-summary.md b/packages/http-specs/spec-summary.md index af295728cc2..a06e312c184 100644 --- a/packages/http-specs/spec-summary.md +++ b/packages/http-specs/spec-summary.md @@ -2835,6 +2835,55 @@ Two requests need to be tested. } ``` +### Payload_Pageable_XmlPagination_list + +- Endpoint: `get /payload/pageable/xml/list` + +Test case for XML pagination with continuation token. Continuation token is passed in the request query and response body. + +Two requests need to be tested. + +1. Initial request: + Expected route: /payload/pageable/xml/list + +Expected response body: + +```xml + + + + 1 + dog + + + 2 + cat + + + page2 + +``` + +2. Next page request: + Expected route: /payload/pageable/xml/list?marker=page2 + +Expected response body: + +```xml + + + + 3 + bird + + + 4 + fish + + + +``` + ### Payload_Xml_ModelWithArrayOfModelValue_get - Endpoint: `get /payload/xml/modelWithArrayOfModel` diff --git a/packages/http-specs/specs/payload/pageable/main.tsp b/packages/http-specs/specs/payload/pageable/main.tsp index 63f7d30e4ee..f2c0af37a55 100644 --- a/packages/http-specs/specs/payload/pageable/main.tsp +++ b/packages/http-specs/specs/payload/pageable/main.tsp @@ -1,8 +1,10 @@ import "@typespec/http"; import "@typespec/spector"; +import "@typespec/xml"; using Http; using Spector; +using TypeSpec.Xml; /** * Test for pageable payload. @@ -514,3 +516,77 @@ namespace PageSize { pets: Pet[]; }; } + +@doc("An XML pet item.") +@name("Pet") +model XmlPet { + @name("Id") id: string; + @name("Name") name: string; +} + +@route("/xml") +namespace XmlPagination { + @scenario + @scenarioDoc(""" + Test case for XML pagination with continuation token. Continuation token is passed in the request query and response body. + + Two requests need to be tested. + + 1. Initial request: + Expected route: /payload/pageable/xml/list + + Expected response body: + ```xml + + + + 1 + dog + + + 2 + cat + + + page2 + + ``` + + 2. Next page request: + Expected route: /payload/pageable/xml/list?marker=page2 + + Expected response body: + ```xml + + + + 3 + bird + + + 4 + fish + + + + ``` + """) + @route("/list") + @list + op list(@continuationToken @query marker?: string): { + @header("content-type") contentType: "application/xml"; + @body body: XmlPetListResult; + }; +} + +@doc("The XML response for listing pets.") +@name("PetListResult") +model XmlPetListResult { + @pageItems + @name("Pets") + pets: XmlPet[]; + + @continuationToken + @name("NextMarker") + nextMarker?: string; +} diff --git a/packages/http-specs/specs/payload/pageable/mockapi.ts b/packages/http-specs/specs/payload/pageable/mockapi.ts index 565bfde9ace..3c5e5e9f0a0 100644 --- a/packages/http-specs/specs/payload/pageable/mockapi.ts +++ b/packages/http-specs/specs/payload/pageable/mockapi.ts @@ -6,6 +6,7 @@ import { passOnSuccess, ScenarioMockApi, ValidationError, + xml, } from "@typespec/spec-api"; export const Scenarios: Record = {}; @@ -511,3 +512,111 @@ Scenarios.Payload_Pageable_ServerDrivenPagination_ContinuationToken_requestHeade kind: "MockApiDefinition", }, ]); + +const XmlFirstPage = ` + + + + 1 + dog + + + 2 + cat + + + page2 + +`; + +const XmlSecondPage = ` + + + + 3 + bird + + + 4 + fish + + + +`; + +Scenarios.Payload_Pageable_XmlPagination_list = passOnSuccess([ + { + uri: "/payload/pageable/xml/list", + method: "get", + request: {}, + response: { + status: 200, + body: xml(XmlFirstPage), + headers: { + "content-type": "application/xml", + }, + }, + handler: (req: MockRequest) => { + const marker = req.query?.marker; + + switch (marker) { + case undefined: + return { + status: 200, + body: xml(XmlFirstPage), + headers: { + "content-type": "application/xml", + }, + }; + case "page2": + return { + status: 200, + body: xml(XmlSecondPage), + headers: { + "content-type": "application/xml", + }, + }; + default: + throw new ValidationError("Unsupported marker", `"undefined" | "page2"`, marker); + } + }, + kind: "MockApiDefinition", + }, + { + uri: "/payload/pageable/xml/list", + method: "get", + request: { query: { marker: "page2" } }, + response: { + status: 200, + body: xml(XmlSecondPage), + headers: { + "content-type": "application/xml", + }, + }, + handler: (req: MockRequest) => { + const marker = req.query?.marker; + + switch (marker) { + case undefined: + return { + status: 200, + body: xml(XmlFirstPage), + headers: { + "content-type": "application/xml", + }, + }; + case "page2": + return { + status: 200, + body: xml(XmlSecondPage), + headers: { + "content-type": "application/xml", + }, + }; + default: + throw new ValidationError("Unsupported marker", `"undefined" | "page2"`, marker); + } + }, + kind: "MockApiDefinition", + }, +]); From e48b5492f219fbd20ac07af0bed488621eb23e39 Mon Sep 17 00:00:00 2001 From: iscai-msft Date: Fri, 23 Jan 2026 15:43:46 -0500 Subject: [PATCH 2/5] add changeset --- .chronus/changes/specs-xmlPaging-2026-0-23-15-43-39.md | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .chronus/changes/specs-xmlPaging-2026-0-23-15-43-39.md diff --git a/.chronus/changes/specs-xmlPaging-2026-0-23-15-43-39.md b/.chronus/changes/specs-xmlPaging-2026-0-23-15-43-39.md new file mode 100644 index 00000000000..d318db5c1ef --- /dev/null +++ b/.chronus/changes/specs-xmlPaging-2026-0-23-15-43-39.md @@ -0,0 +1,7 @@ +--- +changeKind: feature +packages: + - "@typespec/http-specs" +--- + +Add test for xml paging \ No newline at end of file From 432ff9678344bb55b022a5d695dfc4a68fdbbf3a Mon Sep 17 00:00:00 2001 From: iscai-msft Date: Fri, 23 Jan 2026 16:36:02 -0500 Subject: [PATCH 3/5] address tim's comments --- packages/http-specs/specs/payload/pageable/main.tsp | 6 +++--- packages/http-specs/specs/payload/pageable/mockapi.ts | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/http-specs/specs/payload/pageable/main.tsp b/packages/http-specs/specs/payload/pageable/main.tsp index f2c0af37a55..8dc251ac09a 100644 --- a/packages/http-specs/specs/payload/pageable/main.tsp +++ b/packages/http-specs/specs/payload/pageable/main.tsp @@ -4,7 +4,7 @@ import "@typespec/xml"; using Http; using Spector; -using TypeSpec.Xml; +using Xml; /** * Test for pageable payload. @@ -571,9 +571,9 @@ namespace XmlPagination { ``` """) - @route("/list") + @route("/list-with-continuation") @list - op list(@continuationToken @query marker?: string): { + op listWithContinuation(@continuationToken @query marker?: string): { @header("content-type") contentType: "application/xml"; @body body: XmlPetListResult; }; diff --git a/packages/http-specs/specs/payload/pageable/mockapi.ts b/packages/http-specs/specs/payload/pageable/mockapi.ts index 3c5e5e9f0a0..d6b8f9513cb 100644 --- a/packages/http-specs/specs/payload/pageable/mockapi.ts +++ b/packages/http-specs/specs/payload/pageable/mockapi.ts @@ -544,9 +544,9 @@ const XmlSecondPage = ` `; -Scenarios.Payload_Pageable_XmlPagination_list = passOnSuccess([ +Scenarios.Payload_Pageable_XmlPagination_listWithContinuation = passOnSuccess([ { - uri: "/payload/pageable/xml/list", + uri: "/payload/pageable/xml/list-with-continuation", method: "get", request: {}, response: { @@ -583,7 +583,7 @@ Scenarios.Payload_Pageable_XmlPagination_list = passOnSuccess([ kind: "MockApiDefinition", }, { - uri: "/payload/pageable/xml/list", + uri: "/payload/pageable/xml/list-with-continuation", method: "get", request: { query: { marker: "page2" } }, response: { From 354b17b39b8e45839d41b96d2955c710915e5fa8 Mon Sep 17 00:00:00 2001 From: iscai-msft Date: Fri, 23 Jan 2026 16:52:30 -0500 Subject: [PATCH 4/5] add next link paging test as well --- ...cs-xmlNextLinkPaging-2026-1-23-16-47-56.md | 7 ++ packages/http-specs/spec-summary.md | 53 +++++++++++- .../specs/payload/pageable/main.tsp | 74 ++++++++++++++-- .../specs/payload/pageable/mockapi.ts | 86 +++++++++++++++++-- 4 files changed, 205 insertions(+), 15 deletions(-) create mode 100644 .chronus/changes/specs-xmlNextLinkPaging-2026-1-23-16-47-56.md diff --git a/.chronus/changes/specs-xmlNextLinkPaging-2026-1-23-16-47-56.md b/.chronus/changes/specs-xmlNextLinkPaging-2026-1-23-16-47-56.md new file mode 100644 index 00000000000..00a0b7262f1 --- /dev/null +++ b/.chronus/changes/specs-xmlNextLinkPaging-2026-1-23-16-47-56.md @@ -0,0 +1,7 @@ +--- +changeKind: feature +packages: + - "@typespec/http-specs" +--- + +Add test for xml pagination with next link diff --git a/packages/http-specs/spec-summary.md b/packages/http-specs/spec-summary.md index a06e312c184..0ddeea65523 100644 --- a/packages/http-specs/spec-summary.md +++ b/packages/http-specs/spec-summary.md @@ -2835,9 +2835,9 @@ Two requests need to be tested. } ``` -### Payload_Pageable_XmlPagination_list +### Payload_Pageable_XmlPagination_listWithContinuation -- Endpoint: `get /payload/pageable/xml/list` +- Endpoint: `get /payload/pageable/xml/list-with-continuation` Test case for XML pagination with continuation token. Continuation token is passed in the request query and response body. @@ -2884,6 +2884,55 @@ Expected response body: ``` +### Payload_Pageable_XmlPagination_listWithNextLink + +- Endpoint: `get /payload/pageable/xml/list-with-next-link` + +Test case for XML pagination with next link. + +Two requests need to be tested. + +1. Initial request: + Expected route: /payload/pageable/xml/list-with-next-link + +Expected response body: + +```xml + + + + 1 + dog + + + 2 + cat + + + http://[host]:[port]/payload/pageable/xml/list-with-next-link/nextPage + +``` + +2. Next page request: + Expected route: /payload/pageable/xml/list-with-next-link/nextPage + +Expected response body: + +```xml + + + + 3 + bird + + + 4 + fish + + + +``` + ### Payload_Xml_ModelWithArrayOfModelValue_get - Endpoint: `get /payload/xml/modelWithArrayOfModel` diff --git a/packages/http-specs/specs/payload/pageable/main.tsp b/packages/http-specs/specs/payload/pageable/main.tsp index 8dc251ac09a..9173a18490e 100644 --- a/packages/http-specs/specs/payload/pageable/main.tsp +++ b/packages/http-specs/specs/payload/pageable/main.tsp @@ -529,12 +529,12 @@ namespace XmlPagination { @scenario @scenarioDoc(""" Test case for XML pagination with continuation token. Continuation token is passed in the request query and response body. - + Two requests need to be tested. - + 1. Initial request: Expected route: /payload/pageable/xml/list - + Expected response body: ```xml @@ -551,10 +551,10 @@ namespace XmlPagination { page2 ``` - + 2. Next page request: Expected route: /payload/pageable/xml/list?marker=page2 - + Expected response body: ```xml @@ -577,6 +577,58 @@ namespace XmlPagination { @header("content-type") contentType: "application/xml"; @body body: XmlPetListResult; }; + + @scenario + @scenarioDoc(""" + Test case for XML pagination with next link. + + Two requests need to be tested. + + 1. Initial request: + Expected route: /payload/pageable/xml/list-with-next-link + + Expected response body: + ```xml + + + + 1 + dog + + + 2 + cat + + + http://[host]:[port]/payload/pageable/xml/list-with-next-link/nextPage + + ``` + + 2. Next page request: + Expected route: /payload/pageable/xml/list-with-next-link/nextPage + + Expected response body: + ```xml + + + + 3 + bird + + + 4 + fish + + + + ``` + """) + @route("/list-with-next-link") + @list + op listWithNextLink(): { + @header("content-type") contentType: "application/xml"; + @body body: XmlPetListResultWithNextLink; + }; } @doc("The XML response for listing pets.") @@ -590,3 +642,15 @@ model XmlPetListResult { @name("NextMarker") nextMarker?: string; } + +@doc("The XML response for listing pets with next link.") +@name("PetListResult") +model XmlPetListResultWithNextLink { + @pageItems + @name("Pets") + pets: XmlPet[]; + + @nextLink + @name("NextLink") + nextLink?: url; +} diff --git a/packages/http-specs/specs/payload/pageable/mockapi.ts b/packages/http-specs/specs/payload/pageable/mockapi.ts index d6b8f9513cb..e6001f88648 100644 --- a/packages/http-specs/specs/payload/pageable/mockapi.ts +++ b/packages/http-specs/specs/payload/pageable/mockapi.ts @@ -513,7 +513,7 @@ Scenarios.Payload_Pageable_ServerDrivenPagination_ContinuationToken_requestHeade }, ]); -const XmlFirstPage = ` +const XmlContTokenFirstPage = ` @@ -529,7 +529,7 @@ const XmlFirstPage = ` `; -const XmlSecondPage = ` +const XmlContTokenSecondPage = ` @@ -544,6 +544,7 @@ const XmlSecondPage = ` `; + Scenarios.Payload_Pageable_XmlPagination_listWithContinuation = passOnSuccess([ { uri: "/payload/pageable/xml/list-with-continuation", @@ -551,7 +552,7 @@ Scenarios.Payload_Pageable_XmlPagination_listWithContinuation = passOnSuccess([ request: {}, response: { status: 200, - body: xml(XmlFirstPage), + body: xml(XmlContTokenFirstPage), headers: { "content-type": "application/xml", }, @@ -563,7 +564,7 @@ Scenarios.Payload_Pageable_XmlPagination_listWithContinuation = passOnSuccess([ case undefined: return { status: 200, - body: xml(XmlFirstPage), + body: xml(XmlContTokenFirstPage), headers: { "content-type": "application/xml", }, @@ -571,7 +572,7 @@ Scenarios.Payload_Pageable_XmlPagination_listWithContinuation = passOnSuccess([ case "page2": return { status: 200, - body: xml(XmlSecondPage), + body: xml(XmlContTokenSecondPage), headers: { "content-type": "application/xml", }, @@ -588,7 +589,7 @@ Scenarios.Payload_Pageable_XmlPagination_listWithContinuation = passOnSuccess([ request: { query: { marker: "page2" } }, response: { status: 200, - body: xml(XmlSecondPage), + body: xml(XmlContTokenSecondPage), headers: { "content-type": "application/xml", }, @@ -600,7 +601,7 @@ Scenarios.Payload_Pageable_XmlPagination_listWithContinuation = passOnSuccess([ case undefined: return { status: 200, - body: xml(XmlFirstPage), + body: xml(XmlContTokenFirstPage), headers: { "content-type": "application/xml", }, @@ -608,7 +609,7 @@ Scenarios.Payload_Pageable_XmlPagination_listWithContinuation = passOnSuccess([ case "page2": return { status: 200, - body: xml(XmlSecondPage), + body: xml(XmlContTokenSecondPage), headers: { "content-type": "application/xml", }, @@ -620,3 +621,72 @@ Scenarios.Payload_Pageable_XmlPagination_listWithContinuation = passOnSuccess([ kind: "MockApiDefinition", }, ]); + +const xmlNextLinkFirstPage = (baseUrl: string) => ` + + + + 1 + dog + + + 2 + cat + + + ${baseUrl}/payload/pageable/xml/list-with-next-link/nextPage + +`; + +const XmlNextLinkSecondPage = ` + + + + 3 + bird + + + 4 + fish + + + +`; + +Scenarios.Payload_Pageable_XmlPagination_listWithNextLink = passOnSuccess([ + { + uri: "/payload/pageable/xml/list-with-next-link", + method: "get", + request: {}, + response: { + status: 200, + body: xml(xmlNextLinkFirstPage("PLACEHOLDER_BASE_URL")), + headers: { + "content-type": "application/xml", + }, + }, + handler: (req: MockRequest) => { + return { + status: 200, + body: xml(xmlNextLinkFirstPage(req.baseUrl)), + headers: { + "content-type": "application/xml", + }, + }; + }, + kind: "MockApiDefinition", + }, + { + uri: "/payload/pageable/xml/list-with-next-link/nextPage", + method: "get", + request: {}, + response: { + status: 200, + body: xml(XmlNextLinkSecondPage), + headers: { + "content-type": "application/xml", + }, + }, + kind: "MockApiDefinition", + }, +]); From a566557f345ee3e7bca3b3c76faf95cb427563a4 Mon Sep 17 00:00:00 2001 From: Yuchao Yan Date: Mon, 26 Jan 2026 11:34:56 +0800 Subject: [PATCH 5/5] fix format --- .../specs/payload/pageable/main.tsp | 20 +++++++++---------- .../specs/payload/pageable/mockapi.ts | 1 - 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/packages/http-specs/specs/payload/pageable/main.tsp b/packages/http-specs/specs/payload/pageable/main.tsp index 9173a18490e..a717076947e 100644 --- a/packages/http-specs/specs/payload/pageable/main.tsp +++ b/packages/http-specs/specs/payload/pageable/main.tsp @@ -529,12 +529,12 @@ namespace XmlPagination { @scenario @scenarioDoc(""" Test case for XML pagination with continuation token. Continuation token is passed in the request query and response body. - + Two requests need to be tested. - + 1. Initial request: Expected route: /payload/pageable/xml/list - + Expected response body: ```xml @@ -551,10 +551,10 @@ namespace XmlPagination { page2 ``` - + 2. Next page request: Expected route: /payload/pageable/xml/list?marker=page2 - + Expected response body: ```xml @@ -581,12 +581,12 @@ namespace XmlPagination { @scenario @scenarioDoc(""" Test case for XML pagination with next link. - + Two requests need to be tested. - + 1. Initial request: Expected route: /payload/pageable/xml/list-with-next-link - + Expected response body: ```xml @@ -603,10 +603,10 @@ namespace XmlPagination { http://[host]:[port]/payload/pageable/xml/list-with-next-link/nextPage ``` - + 2. Next page request: Expected route: /payload/pageable/xml/list-with-next-link/nextPage - + Expected response body: ```xml diff --git a/packages/http-specs/specs/payload/pageable/mockapi.ts b/packages/http-specs/specs/payload/pageable/mockapi.ts index e6001f88648..3fdbf8c794e 100644 --- a/packages/http-specs/specs/payload/pageable/mockapi.ts +++ b/packages/http-specs/specs/payload/pageable/mockapi.ts @@ -544,7 +544,6 @@ const XmlContTokenSecondPage = ` `; - Scenarios.Payload_Pageable_XmlPagination_listWithContinuation = passOnSuccess([ { uri: "/payload/pageable/xml/list-with-continuation",