Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add tests with 77% statement coverage #41

Merged
merged 8 commits into from
Apr 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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