@@ -63,6 +63,19 @@ describe('PerplexitySearchClient', () => {
6363 } )
6464 } )
6565
66+ it ( 'falls back to env when explicit apiKey is blank' , async ( ) => {
67+ const fetchMock = makeFetchMock ( { results : [ ] } )
68+ const client = new PerplexitySearchClient ( {
69+ apiKey : ' ' ,
70+ fetch : fetchMock as any ,
71+ } )
72+
73+ await client . search ( { query : 'q' } )
74+
75+ const headers = fetchMock . mock . calls [ 0 ] ! [ 1 ] . headers as Record < string , string >
76+ expect ( headers . Authorization ) . toBe ( 'Bearer test-key' )
77+ } )
78+
6679 it ( 'forwards optional filters in the request body' , async ( ) => {
6780 const fetchMock = makeFetchMock ( { results : [ ] } )
6881 const client = new PerplexitySearchClient ( { fetch : fetchMock as any } )
@@ -110,6 +123,36 @@ describe('PerplexitySearchClient', () => {
110123 ) . rejects . toThrow ( / n o n - e m p t y ` q u e r y ` / i)
111124 } )
112125
126+ it ( 'throws when query is whitespace only' , async ( ) => {
127+ const fetchMock = makeFetchMock ( { results : [ ] } )
128+ const client = new PerplexitySearchClient ( { fetch : fetchMock as any } )
129+ await expect ( client . search ( { query : ' ' } ) ) . rejects . toThrow (
130+ / n o n - e m p t y ` q u e r y ` / i,
131+ )
132+ expect ( fetchMock ) . not . toHaveBeenCalled ( )
133+ } )
134+
135+ it ( 'trims query and clamps max_results before forwarding' , async ( ) => {
136+ const fetchMock = makeFetchMock ( { results : [ ] } )
137+ const client = new PerplexitySearchClient ( { fetch : fetchMock as any } )
138+ await client . search ( { query : ' mars rover ' , max_results : 99 } )
139+
140+ const body = JSON . parse ( fetchMock . mock . calls [ 0 ] ! [ 1 ] . body as string )
141+ expect ( body ) . toEqual ( {
142+ query : 'mars rover' ,
143+ max_results : 20 ,
144+ } )
145+ } )
146+
147+ it ( 'clamps max_results to the minimum before forwarding' , async ( ) => {
148+ const fetchMock = makeFetchMock ( { results : [ ] } )
149+ const client = new PerplexitySearchClient ( { fetch : fetchMock as any } )
150+ await client . search ( { query : 'q' , max_results : 0 } )
151+
152+ const body = JSON . parse ( fetchMock . mock . calls [ 0 ] ! [ 1 ] . body as string )
153+ expect ( body . max_results ) . toBe ( 1 )
154+ } )
155+
113156 it ( 'falls back to PPLX_API_KEY when PERPLEXITY_API_KEY is not set' , async ( ) => {
114157 delete process . env . PERPLEXITY_API_KEY
115158 process . env . PPLX_API_KEY = 'fallback-key'
@@ -120,6 +163,16 @@ describe('PerplexitySearchClient', () => {
120163 expect ( headers . Authorization ) . toBe ( 'Bearer fallback-key' )
121164 } )
122165
166+ it ( 'ignores whitespace-only PERPLEXITY_API_KEY when PPLX_API_KEY is set' , async ( ) => {
167+ process . env . PERPLEXITY_API_KEY = ' '
168+ process . env . PPLX_API_KEY = 'fallback-key'
169+ const fetchMock = makeFetchMock ( { results : [ ] } )
170+ const client = new PerplexitySearchClient ( { fetch : fetchMock as any } )
171+ await client . search ( { query : 'q' } )
172+ const headers = fetchMock . mock . calls [ 0 ] ! [ 1 ] . headers as Record < string , string >
173+ expect ( headers . Authorization ) . toBe ( 'Bearer fallback-key' )
174+ } )
175+
123176 it ( 'throws if neither env var is set and no apiKey is passed' , ( ) => {
124177 delete process . env . PERPLEXITY_API_KEY
125178 delete process . env . PPLX_API_KEY
0 commit comments