Skip to content
Merged
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
changeKind: feature
packages:
- "@typespec/http-specs"
---

add test for discriminator model without subtypes and query params with `$` prefixes
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
# Change versionKind to one of: internal, fix, dependencies, feature, deprecation, breaking
changeKind: internal
packages:
- "@typespec/http-client-js"
---

skip some spector tests
4 changes: 4 additions & 0 deletions packages/http-client-js/.testignore
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,7 @@ type/union/discriminated
# Multipart - https://github.com/microsoft/typespec/issues/9155

payload/multipart

# Body root issues - https://github.com/microsoft/typespec/issues/10877

parameters/body-root
51 changes: 51 additions & 0 deletions packages/http-specs/spec-summary.md
Original file line number Diff line number Diff line change
Expand Up @@ -1455,6 +1455,22 @@ Expected request body:
{ "name": "foo" }
```

### Parameters_BodyRoot_nested

- Endpoint: `post /parameters/body-root/nested`

Test case for a `@bodyRoot` parameter nested inside a wrapper model.

Emitters must resolve the accessor path through the wrapper (e.g.
`body.bodyRootParameters`) rather than referencing the property name
directly.

Expected request body:

```json
{ "category": "widget", "linkType": "hard", "wasSuccessful": true }
```

### Parameters_CollectionFormat_Header_csv

- Endpoint: `get /parameters/collection-format/header/csv`
Expand Down Expand Up @@ -1534,6 +1550,18 @@ Second request path:

Expect to handle a constant value for query and mock api returns nothing

### Parameters_Query_SpecialChar_dollarSign

- Endpoint: `get /parameters/query/special-char/dollarSign`

Send a request with a dollar-sign prefixed`$filter` query parameter.

Expected query parameter:

- `$filter` = "status eq 'active'"

Expected response status code: 204

### Parameters_Spread_Alias_spreadAsRequestBody

- Endpoint: `put /parameters/spread/alias/request-body`
Expand Down Expand Up @@ -6226,6 +6254,18 @@ Expected response body:
{ "wingspan": 1, "kind": "sparrow" }
```

### Type_Model_Inheritance_SingleDiscriminator_getNoSubtypesModel

- Endpoint: `get /type/model/inheritance/single-discriminator/no-subtypes/model`

Generate and receive a discriminated model that has no defined subtypes.
The base model declares a discriminator but no models extend it.
Expected response body:

```json
{ "kind": "salmon", "size": 10 }
```

### Type_Model_Inheritance_SingleDiscriminator_getRecursiveModel

- Endpoint: `get /type/model/inheritance/single-discriminator/recursivemodel`
Expand Down Expand Up @@ -6278,6 +6318,17 @@ Expected input body:
{ "wingspan": 1, "kind": "sparrow" }
```

### Type_Model_Inheritance_SingleDiscriminator_putNoSubtypesModel

- Endpoint: `put /type/model/inheritance/single-discriminator/no-subtypes/model`

Send a discriminated model that has no defined subtypes.
Expected input body:

```json
{ "kind": "salmon", "size": 10 }
```

### Type_Model_Inheritance_SingleDiscriminator_putRecursiveModel

- Endpoint: `put /type/model/inheritance/single-discriminator/recursivemodel`
Expand Down
36 changes: 36 additions & 0 deletions packages/http-specs/specs/parameters/body-root/main.tsp
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import "@typespec/http";
import "@typespec/spector";
Comment thread
iscai-msft marked this conversation as resolved.

using Http;
using Spector;

@doc("Test for @bodyRoot parameter patterns.")
@scenarioService("/parameters/body-root")
namespace Parameters.BodyRoot;

model BodyRootModel {
category?: string;
linkType?: string;
wasSuccessful?: boolean;
}

@scenario
@scenarioDoc("""
Test case for a \`@bodyRoot\` parameter nested inside a wrapper model.

Emitters must resolve the accessor path through the wrapper (e.g.
\`body.bodyRootParameters\`) rather than referencing the property name
directly.

Expected request body:
\`\`\`json
{ "category": "widget", "linkType": "hard", "wasSuccessful": true }
\`\`\`
""")
@route("/nested")
@post
op nested(
body: {
@bodyRoot bodyRootParameters: BodyRootModel;
},
Comment thread
iscai-msft marked this conversation as resolved.
): NoContentResponse;
19 changes: 19 additions & 0 deletions packages/http-specs/specs/parameters/body-root/mockapi.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { json, passOnSuccess, ScenarioMockApi } from "@typespec/spec-api";

export const Scenarios: Record<string, ScenarioMockApi> = {};

Scenarios.Parameters_BodyRoot_nested = passOnSuccess({
uri: "/parameters/body-root/nested",
method: "post",
request: {
body: json({
category: "widget",
linkType: "hard",
wasSuccessful: true,
}),
},
response: {
status: 204,
},
kind: "MockApiDefinition",
});
20 changes: 20 additions & 0 deletions packages/http-specs/specs/parameters/query/main.tsp
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,23 @@ interface Constant {
queryParam: "constantValue",
): void;
}

@doc("Special char query parameter verification")
@route("/special-char")
interface SpecialChar {
@scenario
@scenarioDoc("""
Send a request with a dollar-sign prefixed`$filter` query parameter.

Expected query parameter:
- `$filter` = "status eq 'active'"

Expected response status code: 204
""")
@route("/dollarSign")
@get
dollarSign(
Comment thread
iscai-msft marked this conversation as resolved.
@query("$filter")
filter: string,
): void;
}
12 changes: 12 additions & 0 deletions packages/http-specs/specs/parameters/query/mockapi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,15 @@ Scenarios.Parameters_Query_Constant_post = passOnSuccess({
},
kind: "MockApiDefinition",
});

Scenarios.Parameters_Query_SpecialChar_dollarSign = passOnSuccess({
uri: "/parameters/query/special-char/dollar-sign",

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This path doesn't match the route in the tsp.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems like Copilot should have caught this but it didn't run.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Try to fix it in #10963

method: "get",
request: {
query: { $filter: "status eq 'active'" },
},
response: {
status: 204,
},
kind: "MockApiDefinition",
});
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,13 @@ model TRex extends Dinosaur {
kind: "t-rex";
}

@doc("A discriminated model with no defined subtypes. The discriminator is declared but no models extend it.")
@discriminator("kind")
model Fish {
kind: string;
size: int32;
}

@scenario
@route("/model")
@scenarioDoc("""
Expand Down Expand Up @@ -170,3 +177,28 @@ op getWrongDiscriminator(): Bird;
""")
@get
op getLegacyModel(): Dinosaur;

@scenario
@route("/no-subtypes/model")
@scenarioDoc("""
Generate and receive a discriminated model that has no defined subtypes.
The base model declares a discriminator but no models extend it.
Expected response body:
```json
{"kind": "salmon", "size": 10}
```
""")
@get
op getNoSubtypesModel(): Fish;

@scenario
@route("/no-subtypes/model")
@scenarioDoc("""
Send a discriminated model that has no defined subtypes.
Expected input body:
```json
{"kind": "salmon", "size": 10}
```
""")
@put
op putNoSubtypesModel(@body input: Fish): NoContentResponse;
Original file line number Diff line number Diff line change
Expand Up @@ -101,3 +101,31 @@ Scenarios.Type_Model_Inheritance_SingleDiscriminator_getLegacyModel = passOnSucc
},
kind: "MockApiDefinition",
});

const noSubtypesBody = {
kind: "salmon",
size: 10,
};

Scenarios.Type_Model_Inheritance_SingleDiscriminator_getNoSubtypesModel = passOnSuccess({
uri: "/type/model/inheritance/single-discriminator/no-subtypes/model",
method: "get",
request: {},
response: {
status: 200,
body: json(noSubtypesBody),
},
kind: "MockApiDefinition",
});

Scenarios.Type_Model_Inheritance_SingleDiscriminator_putNoSubtypesModel = passOnSuccess({
uri: "/type/model/inheritance/single-discriminator/no-subtypes/model",
method: "put",
request: {
body: json(noSubtypesBody),
},
response: {
status: 204,
},
kind: "MockApiDefinition",
});
Loading