Skip to content
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
2 changes: 1 addition & 1 deletion .github/workflows/pr-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ jobs:
run: yarn lint:css

- name: Run tests
run: yarn test --ci --watch=false
run: yarn test

- name: Build
run: yarn build
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ You can adjust the port by setting the `PORT` environment variable.

## Running the tests

Jest is used as a test runner in this project:
Vitest is used as a test runner in this project:

```
yarn test
Expand All @@ -87,7 +87,7 @@ You can also use watch-mode and display the current test coverage:

```
yarn test:watch
yarm test:coverage
yarn test:coverage
```

### Coding style tests
Expand Down
23 changes: 9 additions & 14 deletions app/__mocks__/redis.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,20 @@
/* eslint-disable no-underscore-dangle */

const store = new Map();
const store = new Map<string, string>();

const mockGet = jest.fn(async key => store.get(key) || null);
const mockSet = jest.fn(async (key, value) => {
export const _get = vi.fn(async (key: string) => store.get(key) || null);
export const _set = vi.fn(async (key: string, value: string) => {
store.set(key, value);
return "OK";
});
const mockConnect = jest.fn(async () => {});
const mockOn = jest.fn();
const mockConnect = vi.fn(async () => {});
const mockOn = vi.fn();

const createClient = jest.fn(() => ({
get: mockGet,
set: mockSet,
export const createClient = vi.fn(() => ({
get: _get,
set: _set,
connect: mockConnect,
on: mockOn,
}));

module.exports = {
createClient,
_get: mockGet,
_set: mockSet,
_reset: () => store.clear(),
};
export const _reset = () => store.clear();
32 changes: 15 additions & 17 deletions app/spec/cache.spec.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
/* eslint-disable no-underscore-dangle */

import * as redis from "redis";
import * as Cache from "../cache";

// eslint-disable-next-line @typescript-eslint/no-require-imports
const redis = require("redis");

jest.mock("redis");
vi.mock("redis", async () => import("../__mocks__/redis"));

describe("cache", () => {
beforeEach(() => {
redis._get.mockClear();
redis._set.mockClear();
redis._reset();
(redis as any)._get.mockClear();

Check warning on line 10 in app/spec/cache.spec.ts

View workflow job for this annotation

GitHub Actions / validate

Unexpected any. Specify a different type
(redis as any)._set.mockClear();

Check warning on line 11 in app/spec/cache.spec.ts

View workflow job for this annotation

GitHub Actions / validate

Unexpected any. Specify a different type
(redis as any)._reset();

Check warning on line 12 in app/spec/cache.spec.ts

View workflow job for this annotation

GitHub Actions / validate

Unexpected any. Specify a different type
});

describe("set", () => {
Expand All @@ -21,10 +19,10 @@

await Cache.set(key, value);

expect(redis._set.mock.calls.length).toBe(1);
expect(redis._set.mock.calls[0][0]).toBe(key);
expect(redis._set.mock.calls[0][1]).toBe(JSON.stringify(value));
expect(redis._set.mock.calls[0][2]).toEqual({ EX: 86400 });
expect((redis as any)._set.mock.calls.length).toBe(1);

Check warning on line 22 in app/spec/cache.spec.ts

View workflow job for this annotation

GitHub Actions / validate

Unexpected any. Specify a different type
expect((redis as any)._set.mock.calls[0][0]).toBe(key);

Check warning on line 23 in app/spec/cache.spec.ts

View workflow job for this annotation

GitHub Actions / validate

Unexpected any. Specify a different type
expect((redis as any)._set.mock.calls[0][1]).toBe(JSON.stringify(value));

Check warning on line 24 in app/spec/cache.spec.ts

View workflow job for this annotation

GitHub Actions / validate

Unexpected any. Specify a different type
expect((redis as any)._set.mock.calls[0][2]).toEqual({ EX: 86400 });

Check warning on line 25 in app/spec/cache.spec.ts

View workflow job for this annotation

GitHub Actions / validate

Unexpected any. Specify a different type
});

it("passes given ttl to redis store", async () => {
Expand All @@ -34,7 +32,7 @@

await Cache.set(key, value, ttl);

expect(redis._set.mock.calls[0][2]).toEqual({ EX: ttl });
expect((redis as any)._set.mock.calls[0][2]).toEqual({ EX: ttl });

Check warning on line 35 in app/spec/cache.spec.ts

View workflow job for this annotation

GitHub Actions / validate

Unexpected any. Specify a different type
});

it("uses 24 hours as default ttl", async () => {
Expand All @@ -43,7 +41,7 @@

await Cache.set(key, value);

expect(redis._set.mock.calls[0][2]).toEqual({ EX: 24 * 60 * 60 });
expect((redis as any)._set.mock.calls[0][2]).toEqual({ EX: 24 * 60 * 60 });
});
});

Expand All @@ -57,8 +55,8 @@
// ignore errors
}

expect(redis._get.mock.calls.length).toBe(1);
expect(redis._get.mock.calls[0][0]).toBe(key);
expect((redis as any)._get.mock.calls.length).toBe(1);
expect((redis as any)._get.mock.calls[0][0]).toBe(key);
});

it("returns correct data from redis store after it was saved", async () => {
Expand All @@ -71,10 +69,10 @@
expect(cachedData).toEqual(value);
});

it("rejects the promise when no data is stored in redis", () => {
it("rejects the promise when no data is stored in redis", async () => {
const key = "foo";

expect(Cache.get(key)).rejects.toBeUndefined();
await expect(Cache.get(key)).rejects.toBeUndefined();
});
});
});
31 changes: 19 additions & 12 deletions components/profile/actions/spec/autoScrobbleActions.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,19 @@ const demoAutoScrobbleData = [
},
];

const mockJsonResponse = data =>
({
ok: true,
status: 200,
json: async () => data,
}) as Response;

describe("historyActions", () => {
let fetchMock;
beforeEach(() => {
fetch.mockResponse(JSON.stringify(demoAutoScrobbleData));
});
afterEach(() => {
fetch.resetMocks();
fetchMock = vi
.spyOn(globalThis, "fetch")
.mockResolvedValue(mockJsonResponse(demoAutoScrobbleData));
});

describe("fetchAutoScrobbles", () => {
Expand Down Expand Up @@ -52,7 +59,7 @@ describe("historyActions", () => {

it("sets error state to store when loading fails", () => {
const error = new Error("Foooo!");
fetch.mockReject(error);
fetchMock.mockRejectedValue(error);
const expectedAction = actionCreators.setErrorState(error);
const store = emptyStore();

Expand All @@ -72,8 +79,8 @@ describe("historyActions", () => {
const store = emptyStore();

return store.dispatch(fetchAutoScrobbles()).then(() => {
expect(fetch.mock.calls.length).toEqual(1);
expect(fetch.mock.calls[0][0]).toEqual("/api/user/autoscrobbles");
expect(fetchMock.mock.calls.length).toEqual(1);
expect(fetchMock.mock.calls[0][0]).toEqual("/api/user/autoscrobbles");
});
});
});
Expand Down Expand Up @@ -110,7 +117,7 @@ describe("historyActions", () => {
it("sets error state to store when loading fails", () => {
const id = 1337;
const error = new Error("Foooo!");
fetch.mockReject(error);
fetchMock.mockRejectedValue(error);
const expectedAction = actionCreators.setErrorState(error);
const store = emptyStore();

Expand All @@ -134,10 +141,10 @@ describe("historyActions", () => {
const store = emptyStore();

return store.dispatch(deleteAutoScrobble(id)).then(() => {
expect(fetch.mock.calls.length).toEqual(1);
expect(fetch.mock.calls[0][0]).toEqual("/api/user/autoscrobbles");
expect(fetch.mock.calls[0][1].method).toEqual("DELETE");
expect(fetch.mock.calls[0][1].body).toEqual(JSON.stringify({ id }));
expect(fetchMock.mock.calls.length).toEqual(1);
expect(fetchMock.mock.calls[0][0]).toEqual("/api/user/autoscrobbles");
expect(fetchMock.mock.calls[0][1].method).toEqual("DELETE");
expect(fetchMock.mock.calls[0][1].body).toEqual(JSON.stringify({ id }));
});
});
});
Expand Down
21 changes: 14 additions & 7 deletions components/profile/actions/spec/historyActions.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,19 @@ const demoHistoryData = [
},
];

const mockJsonResponse = data =>
({
ok: true,
status: 200,
json: async () => data,
}) as Response;

describe("historyActions", () => {
let fetchMock;
beforeEach(() => {
fetch.mockResponse(JSON.stringify(demoHistoryData));
});
afterEach(() => {
fetch.resetMocks();
fetchMock = vi
.spyOn(globalThis, "fetch")
.mockResolvedValue(mockJsonResponse(demoHistoryData));
});

it("sets loading state to true as first action", () => {
Expand All @@ -52,7 +59,7 @@ describe("historyActions", () => {

it("sets error state to store when loading fails", () => {
const error = new Error("Foooo!");
fetch.mockReject(error);
fetchMock.mockRejectedValue(error);
const expectedAction = actionCreators.setErrorState(error);
const store = emptyStore();

Expand All @@ -70,8 +77,8 @@ describe("historyActions", () => {
const store = emptyStore();

return store.dispatch(fetchHistory()).then(() => {
expect(fetch.mock.calls.length).toEqual(1);
expect(fetch.mock.calls[0][0]).toEqual("/api/user/history");
expect(fetchMock.mock.calls.length).toEqual(1);
expect(fetchMock.mock.calls[0][0]).toEqual("/api/user/history");
});
});
});
7 changes: 4 additions & 3 deletions config/setupTests.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import fetchMock from "jest-fetch-mock";

global.fetch = fetchMock as any;
afterEach(() => {
vi.restoreAllMocks();
vi.unstubAllGlobals();
});
22 changes: 12 additions & 10 deletions eslint.config.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
const { FlatCompat } = require("@eslint/eslintrc");
const js = require("@eslint/js");
const prettierConfig = require("eslint-config-prettier/flat");
const vitestModule = require("@vitest/eslint-plugin");

const vitest = vitestModule.default ?? vitestModule;

const compat = new FlatCompat({
baseDirectory: __dirname,
Expand Down Expand Up @@ -29,20 +32,19 @@ module.exports = [
"plugin:import/recommended",
),
{
files: ["**/*.spec.{js,jsx,ts,tsx}", "**/*.test.{js,jsx,ts,tsx}"],
files: ["**/*.{spec,test}.{js,jsx,ts,tsx}"],
plugins: {
vitest,
},
languageOptions: {
globals: {
describe: "readonly",
it: "readonly",
test: "readonly",
expect: "readonly",
beforeAll: "readonly",
beforeEach: "readonly",
afterAll: "readonly",
afterEach: "readonly",
jest: "readonly",
...vitest.environments.env.globals,
},
},
rules: {
...vitest.configs.recommended.rules,
"vitest/no-importing-vitest-globals": "error",
},
},
{
rules: {
Expand Down
16 changes: 0 additions & 16 deletions jest.config.js

This file was deleted.

22 changes: 11 additions & 11 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@
"dev": "next dev",
"build": "next build",
"start": "next start",
"test": "jest",
"test:watch": "yarn test --watch",
"test:coverage": "yarn test --coverage",
"test": "vitest run",
"test:watch": "vitest",
"test:coverage": "vitest run --coverage",
"lint": "eslint .",
"lint:fix": "eslint . --fix",
"lint:css": "stylelint './**/*.styles.ts'",
Expand Down Expand Up @@ -60,21 +60,20 @@
"@lavamoat/preinstall-always-fail": "^2.1.1",
"@testing-library/dom": "^10.0.0",
"@testing-library/react": "^16.0.0",
"@types/jest": "^30.0.0",
"@types/node": "^22.10.7",
"@types/react": "^18.3.18",
"@types/react-dom": "^18.3.5",
"babel-jest": "^29.7.0",
"@vitejs/plugin-react": "^4.4.1",
"@vitest/coverage-v8": "^2.1.8",
"@vitest/eslint-plugin": "^1.3.25",
"babel-plugin-styled-components": "^2.1.4",
"eslint": "^8.57.0",
"eslint-config-next": "^14.2.0",
"eslint-config-prettier": "10.1.8",
"eslint-plugin-import": "^2.31.0",
"eslint-plugin-jsx-a11y": "^6.10.2",
"happy-dom": "^15.11.7",
"husky": "^9.0.0",
"jest": "^29.7.0",
"jest-environment-jsdom": "^29.7.0",
"jest-fetch-mock": "^3.0.1",
"lint-staged": "^16.2.4",
"postcss-styled-syntax": "^0.7.1",
"prettier": "^3.8.1",
Expand All @@ -83,14 +82,15 @@
"redux-mock-store": "^1.5.4",
"stylelint": "^16.12.0",
"stylelint-config-recommended": "^14.0.1",
"typescript": "^5.7.3"
"typescript": "^5.7.3",
"vite": "^6.1.0",
"vite-tsconfig-paths": "^5.1.4",
"vitest": "^2.1.8"
},
"packageManager": "yarn@4.12.0",
"lavamoat": {
"allowScripts": {
"@lavamoat/preinstall-always-fail": false,
"babel-jest>@jest/transform>jest-haste-map>fsevents": false,
"jest-environment-jsdom>jest-util>jest-util>fsevents": false,
"@babel/runtime-corejs2>core-js": false,
"eslint-config-next>eslint-import-resolver-typescript>unrs-resolver": false
}
Expand Down
1 change: 1 addition & 0 deletions types/vitest.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/// <reference types="vitest/globals" />
Loading
Loading