Skip to content

Commit

Permalink
Merge pull request #41 from Firebird1029/backend_tests
Browse files Browse the repository at this point in the history
Add tests with 77% statement coverage
  • Loading branch information
hoixw authored Apr 13, 2024
2 parents 566cbe8 + 762e837 commit 9f1017b
Show file tree
Hide file tree
Showing 40 changed files with 37,099 additions and 1,165 deletions.
3 changes: 3 additions & 0 deletions .babelrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"presets": ["@babel/preset-env"]
}
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ To test the application:
npm test
```

We have achieved 77% statement coverage.

## Linting

To lint the application:
Expand Down
2 changes: 1 addition & 1 deletion __tests__/__snapshots__/frontend.t.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
exports[`Index Component matches the snapshot 1`] = `
<DocumentFragment>
<div
class="flex h-screen relative"
class="flex relative \\ lg:h-screen"
>
<div
class="w-[100%] flex flex-col justify-center items-center text-center hidden"
Expand Down
653 changes: 653 additions & 0 deletions __tests__/__snapshots__/svg_art.t.js.snap

Large diffs are not rendered by default.

79 changes: 79 additions & 0 deletions __tests__/average_audio_features.t.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import axios from "axios";
import { getAverageAudioFeatures } from "../src/spotify";

// Mocking axios
jest.mock("axios");

describe("Spotify API functions", () => {
describe("getAverageAudioFeatures", () => {
afterEach(() => {
jest.clearAllMocks();
});

test("calls getAudioFeatures with correct parameters", async () => {
const token = "testToken";
const topSongs = {
items: [
{ id: "id1", popularity: 70 },
{ id: "id2", popularity: 80 },
],
};

// Spy on getAudioFeatures
const getAudioFeaturesSpy = jest.spyOn(axios, "get");

// Mock the implementation of axios.get to return a resolved promise with dummy data
getAudioFeaturesSpy.mockResolvedValueOnce({
data: {
audio_features: [
{
acousticness: 0.5,
danceability: 0.7,
energy: 0.8,
instrumentalness: 0.3,
speechiness: 0.4,
valence: 0.6,
},
{
acousticness: 0.4,
danceability: 0.6,
energy: 0.7,
instrumentalness: 0.2,
speechiness: 0.5,
valence: 0.8,
},
],
},
});

await getAverageAudioFeatures(token, topSongs);

// Assert that getAudioFeatures was called with the correct parameters
expect(getAudioFeaturesSpy).toHaveBeenCalledWith(
expect.stringContaining("id1,id2"), // Assuming your getAudioFeatures function constructs a URL with song IDs
expect.objectContaining({
headers: { Authorization: `Bearer ${token}` },
}),
);
});

test("throws an error when unable to fetch audio features", async () => {
const token = "testToken";
const topSongs = {
items: [
{ id: "id1", popularity: 70 },
{ id: "id2", popularity: 80 },
],
};

// Mocking the axios.get to return a rejected promise
axios.get.mockRejectedValueOnce(
new Error("Failed to fetch audio features"),
);

await expect(getAverageAudioFeatures(token, topSongs)).rejects.toThrow(
"Error fetching data from Spotify API: Failed to fetch audio features",
);
});
});
});
131 changes: 131 additions & 0 deletions __tests__/backend.t.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
import axios from "axios";
import {
callSpotifyApi,
getUserData,
getTopGenres,
getAudioFeatures,
getTopItems,
} from "../src/spotify";

// Mocking axios
jest.mock("axios");

describe("Spotify API functions", () => {
describe("callSpotifyApi", () => {
test("calls axios.get with correct parameters", async () => {
const token = "testToken";
const endpoint = "/me";
const responseData = { data: "testData" };
axios.get.mockResolvedValue(responseData);

const result = await callSpotifyApi(token, endpoint);

expect(axios.get).toHaveBeenCalledWith(
`https://api.spotify.com/v1${endpoint}`,
{
headers: {
Authorization: `Bearer ${token}`,
},
},
);
expect(result).toEqual(responseData.data);
});

test("throws an error if token is not provided", async () => {
const token = "";
const endpoint = "/me";

await expect(callSpotifyApi(token, endpoint)).rejects.toThrow(
"Token not provided.",
);
});

test("throws an error if response is not valid", async () => {
const token = "testToken";
const endpoint = "/me";
const responseData = null;
axios.get.mockResolvedValue({ data: responseData });

await expect(callSpotifyApi(token, endpoint)).rejects.toThrow(
"Unable to fetch data from Spotify API.",
);
});

test("throws an error if there is an error during API call", async () => {
const token = "testToken";
const endpoint = "/me";
const errorMessage = "Failed to fetch data";
axios.get.mockRejectedValue(new Error(errorMessage));

await expect(callSpotifyApi(token, endpoint)).rejects.toThrow(
`Error fetching data from Spotify API: ${errorMessage}`,
);
});
});

describe("getTopGenres", () => {
test("correctly counts genre frequencies", () => {
const topArtists = [
{ genres: ["pop", "rock"] },
{ genres: ["pop", "jazz"] },
{ genres: ["rock", "hip-hop"] },
];

const result = getTopGenres(topArtists);

expect(result).toEqual({ pop: 2, rock: 2, jazz: 1, "hip-hop": 1 });
});
});

describe("getAudioFeatures", () => {
test("throws an error if ids", async () => {
const token = "";
await expect(getAudioFeatures(token)).rejects.toThrow(
"Ids must be provided.",
);
});
});

describe("getUserData", () => {
test("returns user data when token is provided", async () => {
const token = "testToken";
const userData = { id: "user123", display_name: "Test User" };
axios.get.mockResolvedValue({ data: userData });

const result = await getUserData(token);

expect(result).toEqual(userData);
expect(axios.get).toHaveBeenCalledWith("https://api.spotify.com/v1/me", {
headers: {
Authorization: `Bearer ${token}`,
},
});
});
});

describe("getTopItems", () => {
test("returns top items when token is provided", async () => {
const token = "testToken";
const type = "tracks";
const timeRange = "short_term";
const limit = "5";
const topItemsData = [
{ id: "track1", name: "Track 1" },
{ id: "track2", name: "Track 2" },
];
axios.get.mockResolvedValue({ data: topItemsData });

const result = await getTopItems(token, type, timeRange, limit);

expect(result).toEqual(topItemsData);
expect(axios.get).toHaveBeenCalledWith(
`https://api.spotify.com/v1/me/top/${type}?time_range=${timeRange}&limit=${limit}`,
{
headers: {
Authorization: `Bearer ${token}`,
},
},
);
});
});
});
14 changes: 14 additions & 0 deletions __tests__/error.t.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/* eslint-disable react/jsx-filename-extension */

import React from "react";
import { render, screen, fireEvent } from "@testing-library/react";
import ErrorAlert from "@/app/error/error";

describe("ErrorAlert Component Tests", () => {
// Test for proper rendering with props
it("renders with given title and message", () => {
render(<ErrorAlert Title="Error" Message="An error has occurred" />);
expect(screen.getByText("Error")).toBeInTheDocument();
expect(screen.getByText("An error has occurred")).toBeInTheDocument();
});
});
107 changes: 107 additions & 0 deletions __tests__/get_spotify_data.t.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import axios from "axios";
import { getSpotifyData } from "../src/spotify"; // Replace with the correct path to your module

jest.mock("axios");

describe("getSpotifyData", () => {
const mockToken = "mockToken";

beforeEach(() => {
axios.get.mockClear();
});

test("should fetch user data and return formatted user data", async () => {
const getUserDataSpy = jest.spyOn(axios, "get");
getUserDataSpy.mockResolvedValueOnce({
data: {},
});

const topArtistsShortDataSpy = jest.spyOn(axios, "get");
topArtistsShortDataSpy.mockResolvedValueOnce({
data: {
items: [
{ genres: ["pop", "rock"] },
{ genres: ["pop", "jazz"] },
{ genres: ["rock", "hip-hop"] },
],
},
});
const topArtistsMediumDataSpy = jest.spyOn(axios, "get");
topArtistsMediumDataSpy.mockResolvedValueOnce({
data: {
items: [
{ genres: ["pop", "rock"] },
{ genres: ["pop", "jazz"] },
{ genres: ["rock", "hip-hop"] },
],
},
});
const topArtistsLongDataSpy = jest.spyOn(axios, "get");
topArtistsLongDataSpy.mockResolvedValueOnce({
data: {
items: [
{ genres: ["pop", "rock"] },
{ genres: ["pop", "jazz"] },
{ genres: ["rock", "hip-hop"] },
],
},
});

const topSongsShortDataSpy = jest.spyOn(axios, "get");
topSongsShortDataSpy.mockResolvedValueOnce({
data: {},
});
const topSongsMediumDataSpy = jest.spyOn(axios, "get");
topSongsMediumDataSpy.mockResolvedValueOnce({
data: {},
});
const topSongsLongDataSpy = jest.spyOn(axios, "get");
topSongsLongDataSpy.mockResolvedValueOnce({
data: { items: Array(50).fill(0) },
});

// Spy on getAudioFeatures
const getAudioFeaturesSpy = jest.spyOn(axios, "get");

// Mock the implementation of axios.get to return a resolved promise with dummy data
getAudioFeaturesSpy.mockResolvedValueOnce({
data: {
audio_features: [
{
acousticness: 0.5,
danceability: 0.7,
energy: 0.8,
instrumentalness: 0.3,
speechiness: 0.4,
valence: 0.6,
},
{
acousticness: 0.4,
danceability: 0.6,
energy: 0.7,
instrumentalness: 0.2,
speechiness: 0.5,
valence: 0.8,
},
],
},
});

const result = await getSpotifyData(mockToken);

expect(axios.get).toHaveBeenCalledTimes(8);
expect(axios.get).toHaveBeenCalledWith("https://api.spotify.com/v1/me", {
headers: { Authorization: `Bearer ${mockToken}` },
});
expect(axios.get).toHaveBeenCalledWith(
"https://api.spotify.com/v1/me/top/artists?time_range=short_term&limit=25",
{
headers: { Authorization: `Bearer ${mockToken}` },
},
);
});

test("should throw an error if token is not provided", async () => {
await expect(getSpotifyData()).rejects.toThrow("Token not provided.");
});
});
Loading

0 comments on commit 9f1017b

Please sign in to comment.