Skip to content

Commit a56a462

Browse files
authored
fix(Spotify Node): Fix issue with null values breaking the response (#12080)
1 parent 1d86c4f commit a56a462

File tree

7 files changed

+7223
-4
lines changed

7 files changed

+7223
-4
lines changed

Diff for: packages/nodes-base/nodes/Spotify/GenericFunctions.ts

+4-4
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import type {
55
IHookFunctions,
66
JsonObject,
77
IHttpRequestMethods,
8-
IRequestOptions,
8+
IHttpRequestOptions,
99
} from 'n8n-workflow';
1010
import { NodeApiError } from 'n8n-workflow';
1111

@@ -21,23 +21,23 @@ export async function spotifyApiRequest(
2121
query?: IDataObject,
2222
uri?: string,
2323
): Promise<any> {
24-
const options: IRequestOptions = {
24+
const options: IHttpRequestOptions = {
2525
method,
2626
headers: {
2727
'User-Agent': 'n8n',
2828
'Content-Type': 'text/plain',
2929
Accept: ' application/json',
3030
},
3131
qs: query,
32-
uri: uri || `https://api.spotify.com/v1${endpoint}`,
32+
url: uri ?? `https://api.spotify.com/v1${endpoint}`,
3333
json: true,
3434
};
3535

3636
if (Object.keys(body).length > 0) {
3737
options.body = body;
3838
}
3939
try {
40-
return await this.helpers.requestOAuth2.call(this, 'spotifyOAuth2Api', options);
40+
return await this.helpers.httpRequestWithAuthentication.call(this, 'spotifyOAuth2Api', options);
4141
} catch (error) {
4242
throw new NodeApiError(this.getNode(), error as JsonObject);
4343
}

Diff for: packages/nodes-base/nodes/Spotify/Spotify.node.ts

+4
Original file line numberDiff line numberDiff line change
@@ -1308,6 +1308,10 @@ export class Spotify implements INodeType {
13081308
);
13091309
}
13101310

1311+
// Remove null values from the response
1312+
if (operation === 'getUserPlaylists') {
1313+
responseData = responseData.filter((item: IDataObject) => item !== null);
1314+
}
13111315
const executionData = this.helpers.constructExecutionMetaData(
13121316
this.helpers.returnJsonArray(responseData as IDataObject[]),
13131317
{ itemData: { item: i } },
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import type { IExecuteFunctions, IHookFunctions } from 'n8n-workflow';
2+
import { NodeApiError } from 'n8n-workflow';
3+
4+
import { spotifyApiRequest } from '../GenericFunctions';
5+
6+
describe('Spotify -> GenericFunctions', () => {
7+
let mockThis: IHookFunctions | IExecuteFunctions;
8+
9+
beforeEach(() => {
10+
mockThis = {
11+
helpers: {
12+
httpRequestWithAuthentication: jest.fn(),
13+
},
14+
getNode: jest.fn().mockReturnValue({}),
15+
} as unknown as IHookFunctions | IExecuteFunctions;
16+
});
17+
18+
it('should make a request with the correct options', async () => {
19+
const method = 'GET';
20+
const endpoint = '/me';
21+
const body = {};
22+
const query = { limit: 10 };
23+
const response = { data: 'test' };
24+
25+
(mockThis.helpers.httpRequestWithAuthentication as jest.Mock).mockResolvedValue(response);
26+
27+
const result = await spotifyApiRequest.call(mockThis, method, endpoint, body, query);
28+
29+
expect(mockThis.helpers.httpRequestWithAuthentication).toHaveBeenCalledWith(
30+
'spotifyOAuth2Api',
31+
{
32+
method,
33+
headers: {
34+
'User-Agent': 'n8n',
35+
'Content-Type': 'text/plain',
36+
Accept: ' application/json',
37+
},
38+
qs: query,
39+
url: `https://api.spotify.com/v1${endpoint}`,
40+
json: true,
41+
},
42+
);
43+
44+
expect(result).toEqual(response);
45+
});
46+
47+
it('should throw a NodeApiError on request failure', async () => {
48+
const method = 'GET';
49+
const endpoint = '/me';
50+
const body = {};
51+
const query = { limit: 10 };
52+
const error = new Error('Request failed');
53+
54+
(mockThis.helpers.httpRequestWithAuthentication as jest.Mock).mockRejectedValue(error);
55+
56+
await expect(spotifyApiRequest.call(mockThis, method, endpoint, body, query)).rejects.toThrow(
57+
NodeApiError,
58+
);
59+
60+
expect(mockThis.getNode).toHaveBeenCalled();
61+
});
62+
});

0 commit comments

Comments
 (0)