Skip to content

Commit 3e1664e

Browse files
authored
test(query): add regression coverage for vue-query header params (#1026) (#3379)
* test(query): add regression coverage for vue-query header params (#1026) * test(query): tighten #1026 query key getter assertion
1 parent 8fda223 commit 3e1664e

7 files changed

Lines changed: 237 additions & 0 deletions

File tree

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
/**
2+
* Generated by orval v8.11.0 🍺
3+
* Do not edit manually.
4+
* Issue 1026 - Vue Query header parameters
5+
* OpenAPI spec version: 1.0.0
6+
*/
7+
import { useQuery } from '@tanstack/vue-query';
8+
import type {
9+
DataTag,
10+
QueryClient,
11+
QueryFunction,
12+
QueryKey,
13+
UseQueryOptions,
14+
UseQueryReturnType,
15+
} from '@tanstack/vue-query';
16+
17+
import axios from 'axios';
18+
import type { AxiosError, AxiosRequestConfig, AxiosResponse } from 'axios';
19+
20+
import { unref } from 'vue';
21+
import type { MaybeRef } from 'vue';
22+
23+
import type { GetSomeEndpointHeaders, SomeEndpointResult } from './model';
24+
25+
/**
26+
* @summary Get something with header parameters
27+
*/
28+
export const getSomeEndpoint = (
29+
headers?: MaybeRef<GetSomeEndpointHeaders>,
30+
options?: AxiosRequestConfig,
31+
): Promise<AxiosResponse<SomeEndpointResult>> => {
32+
headers = unref(headers);
33+
34+
return axios.get(`/api/v1/someEndPoint`, {
35+
...options,
36+
headers: { ...headers, ...options?.headers },
37+
});
38+
};
39+
40+
export const getGetSomeEndpointQueryKey = () => {
41+
return ['api', 'v1', 'someEndPoint'] as const;
42+
};
43+
44+
export const getGetSomeEndpointQueryOptions = <
45+
TData = Awaited<ReturnType<typeof getSomeEndpoint>>,
46+
TError = AxiosError<unknown>,
47+
>(
48+
headers?: MaybeRef<GetSomeEndpointHeaders>,
49+
options?: {
50+
query?: Partial<
51+
UseQueryOptions<
52+
Awaited<ReturnType<typeof getSomeEndpoint>>,
53+
TError,
54+
TData
55+
>
56+
>;
57+
axios?: AxiosRequestConfig;
58+
},
59+
) => {
60+
const { query: queryOptions, axios: axiosOptions } = options ?? {};
61+
62+
const queryKey = getGetSomeEndpointQueryKey();
63+
64+
const queryFn: QueryFunction<Awaited<ReturnType<typeof getSomeEndpoint>>> = ({
65+
signal,
66+
}) => getSomeEndpoint(headers, { signal, ...axiosOptions });
67+
68+
return { queryKey, queryFn, ...queryOptions } as UseQueryOptions<
69+
Awaited<ReturnType<typeof getSomeEndpoint>>,
70+
TError,
71+
TData
72+
>;
73+
};
74+
75+
export type GetSomeEndpointQueryResult = NonNullable<
76+
Awaited<ReturnType<typeof getSomeEndpoint>>
77+
>;
78+
export type GetSomeEndpointQueryError = AxiosError<unknown>;
79+
80+
/**
81+
* @summary Get something with header parameters
82+
*/
83+
84+
export function useGetSomeEndpoint<
85+
TData = Awaited<ReturnType<typeof getSomeEndpoint>>,
86+
TError = AxiosError<unknown>,
87+
>(
88+
headers?: MaybeRef<GetSomeEndpointHeaders>,
89+
options?: {
90+
query?: Partial<
91+
UseQueryOptions<
92+
Awaited<ReturnType<typeof getSomeEndpoint>>,
93+
TError,
94+
TData
95+
>
96+
>;
97+
axios?: AxiosRequestConfig;
98+
},
99+
queryClient?: QueryClient,
100+
): UseQueryReturnType<TData, TError> & {
101+
queryKey: DataTag<QueryKey, TData, TError>;
102+
} {
103+
const queryOptions = getGetSomeEndpointQueryOptions(headers, options);
104+
105+
const query = useQuery(queryOptions, queryClient) as UseQueryReturnType<
106+
TData,
107+
TError
108+
> & { queryKey: DataTag<QueryKey, TData, TError> };
109+
110+
query.queryKey = unref(queryOptions).queryKey as DataTag<
111+
QueryKey,
112+
TData,
113+
TError
114+
>;
115+
116+
return query;
117+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
/**
2+
* Generated by orval v8.11.0 🍺
3+
* Do not edit manually.
4+
* Issue 1026 - Vue Query header parameters
5+
* OpenAPI spec version: 1.0.0
6+
*/
7+
8+
export type GetSomeEndpointHeaders = {
9+
'Language-Id'?: number;
10+
'Country-Id'?: number;
11+
TimeZone?: string;
12+
};
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
/**
2+
* Generated by orval v8.11.0 🍺
3+
* Do not edit manually.
4+
* Issue 1026 - Vue Query header parameters
5+
* OpenAPI spec version: 1.0.0
6+
*/
7+
8+
export * from './getSomeEndpointHeaders';
9+
export * from './someEndpointResult';
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
/**
2+
* Generated by orval v8.11.0 🍺
3+
* Do not edit manually.
4+
* Issue 1026 - Vue Query header parameters
5+
* OpenAPI spec version: 1.0.0
6+
*/
7+
8+
export interface SomeEndpointResult {
9+
value?: string;
10+
}

tests/api-generation.spec.ts

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,3 +176,36 @@ test('default issue-873 does not duplicate multi-tag operations across tag files
176176
).not.toContain(marker);
177177
}
178178
});
179+
180+
test('vue-query issue-1026 keeps header params out of the query key getter', async () => {
181+
// Regression for #1026: with `headers: true` the Vue Query key getter used to
182+
// emit `headers = unref(headers);` even though `headers` is not one of its
183+
// parameters, throwing `ReferenceError: headers is not defined` at runtime.
184+
// The getter must never unref params (that would also break key reactivity);
185+
// `headers` is only unref'd inside the HTTP function where it is a parameter.
186+
// Keep this focused assertion alongside the snapshot so #1026 fails with a
187+
// targeted message instead of a full-file snapshot diff.
188+
const content = await readFile(
189+
generated('vue-query', 'issue-1026', 'endpoints.ts'),
190+
'utf8',
191+
);
192+
193+
// Slice out the `getGetSomeEndpointQueryKey` declaration body.
194+
const marker = 'export const getGetSomeEndpointQueryKey = (';
195+
const start = content.indexOf(marker);
196+
expect(start, `${marker} should be generated`).toBeGreaterThan(-1);
197+
const end = content.indexOf('as const', start);
198+
expect(end, `${marker} body should be terminated`).toBeGreaterThan(start);
199+
const queryKeyFn = content.slice(start, end);
200+
201+
// The getter must not reference `headers` as an identifier: that was the
202+
// #1026 bug (`headers = unref(headers);`) and unref-ing a param would also
203+
// break query-key reactivity. A word-boundary regex keeps the intent precise
204+
// rather than matching `headers` as a loose substring.
205+
expect(queryKeyFn).not.toMatch(/\bheaders\b/);
206+
207+
// Sanity check: the HTTP function still receives and unrefs `headers`, so the
208+
// assertion above is not passing simply because headers support is missing.
209+
expect(content).toContain('headers?: MaybeRef<GetSomeEndpointHeaders>');
210+
expect(content).toContain('headers = unref(headers);');
211+
});

tests/configs/vue-query.config.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,21 @@ export default defineConfig({
250250
},
251251
input: { target: '../specifications/petstore.yaml' },
252252
},
253+
issue1026: {
254+
output: {
255+
target: '../generated/vue-query/issue-1026/endpoints.ts',
256+
schemas: '../generated/vue-query/issue-1026/model',
257+
client: 'vue-query',
258+
httpClient: 'axios',
259+
mode: 'split',
260+
headers: true,
261+
clean: true,
262+
formatter: 'prettier',
263+
},
264+
input: {
265+
target: '../specifications/issue-1026.yaml',
266+
},
267+
},
253268
// Unsupported for now, see for context: https://github.com/orval-labs/orval/pull/931#issuecomment-1752355686
254269
// namedParameters: {
255270
// output: {
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
openapi: 3.0.0
2+
info:
3+
title: Issue 1026 - Vue Query header parameters
4+
version: 1.0.0
5+
paths:
6+
/api/v1/someEndPoint:
7+
get:
8+
operationId: getSomeEndpoint
9+
tags:
10+
- things
11+
summary: Get something with header parameters
12+
parameters:
13+
- name: Language-Id
14+
in: header
15+
style: simple
16+
schema:
17+
type: integer
18+
- name: Country-Id
19+
in: header
20+
style: simple
21+
schema:
22+
type: integer
23+
- name: TimeZone
24+
in: header
25+
style: simple
26+
schema:
27+
type: string
28+
responses:
29+
'200':
30+
description: OK
31+
content:
32+
application/json:
33+
schema:
34+
$ref: '#/components/schemas/SomeEndpointResult'
35+
components:
36+
schemas:
37+
SomeEndpointResult:
38+
type: object
39+
properties:
40+
value:
41+
type: string

0 commit comments

Comments
 (0)