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

feat: add some tests #43

Merged
merged 2 commits into from
May 20, 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
12 changes: 6 additions & 6 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,12 @@ jobs:

- name: Build Project
run: yarn build


- uses: sonarsource/sonarqube-scan-action@master
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }}

- name: Test and generate coverage report
uses: artiomtr/[email protected]
with:
Expand All @@ -45,11 +50,6 @@ jobs:
skip-step: install
test-script: yarn test
custom-title: Jest Coverage Report

- uses: sonarsource/sonarqube-scan-action@master
env:
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }}

# Commenting out SonarQube Quality Gate action for now
# - uses: sonarsource/sonarqube-quality-gate-action@master
Expand Down
2 changes: 1 addition & 1 deletion jest.config.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Config } from "jest";
import type { Config } from "jest";
import nextJest from "next/jest";

const createJestConfig = nextJest({ dir: "./" });
Expand Down
22 changes: 3 additions & 19 deletions sonar-project.properties
Original file line number Diff line number Diff line change
@@ -1,29 +1,13 @@
# Project identification
sonar.organization=wednesday-solutions
sonar.projectKey=wednesday-solutions_next-bulletproof-ts_AY6yu6eKB2n8RRmGoUz4

# Specify the language
sonar.language=ts

# Source directory
sonar.sources=.

sonar.sources=src
# Test directory
sonar.tests=src

# Exclude node_modules
# Let's not exclude anything for now, after refractoring changes we can decide what to exclude from the analysis
sonar.exclusions=node_modules/**/*,lighthouserc.js

sonar.test.inclusions=**/*.test.tsx,**/*.test.js,**/*.test.ts
sonar.javascript.lcov.reportPaths=./coverage/lcov.info
sonar.testExecutionReportPaths=./reports/test-report.xml

sonar.javascript.lcov.reportPaths=coverage/lcov.info
sonar.testExecutionReportPaths=reports/test-report.xml
# Encoding of the source code
sonar.sourceEncoding=UTF-8

# Coverage report path
sonar.javascript.lcov.reportPaths=coverage/lcov.info

# Test execution report path
sonar.testExecutionReportPaths=./reports/test-report.xml
65 changes: 65 additions & 0 deletions src/common/ErrorBoundary/tests/index.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import React from "react";
import { render } from "@utils/testUtils";
import { ErrorBoundary } from "@app/common";

describe("ErrorBoundary", () => {
it("renders children when there is no error", () => {
const ChildComponent = () => <div>Child Component</div>;
const { getByText } = render(
<ErrorBoundary>
<ChildComponent />
</ErrorBoundary>
);
expect(getByText("Child Component")).toBeDefined();
});

it("renders error message when there is an error", () => {
class TestErrorComponent extends React.Component {
componentDidMount() {
throw new Error("Test error");
}

render() {
return <div>Child Component</div>;
}
}

const { getByText } = render(
<ErrorBoundary>
<TestErrorComponent />
</ErrorBoundary>
);
expect(getByText("Something Went Wrong")).toBeDefined();
});

it("catches error using componentDidCatch", () => {
const mockConsoleError = jest.spyOn(console, "error").mockImplementation(() => {});
class TestErrorComponent extends React.Component {
componentDidMount() {
throw new Error("Test error");
}

render() {
return <div>Child Component</div>;
}
}

render(
<ErrorBoundary>
<TestErrorComponent />
</ErrorBoundary>
);

expect(mockConsoleError).toHaveBeenCalled();
mockConsoleError.mockRestore();
});

it("updates state when error is caught using getDerivedStateFromError", () => {
const error = new Error("Test error");
// const errorBoundaryInstance = new ErrorBoundary({ children: null });

const updatedState = ErrorBoundary.getDerivedStateFromError(error);

expect(updatedState).toEqual({ hasError: true, error });
});
});
15 changes: 15 additions & 0 deletions src/common/Loader/tests/index.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import React from 'react';
import { render } from '@testing-library/react';
import Loader from '../index';

describe('Loader component', () => {
it('renders without crashing', () => {
render(<Loader />);
});

it('renders CircularProgress component', () => {
const { getByRole } = render(<Loader />);
const circularProgress = getByRole('progressbar');
expect(circularProgress).toBeDefined();
});
});
58 changes: 58 additions & 0 deletions src/features/repos/api/tests/getRecommendations.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { IResponse } from "../getRecommendations";

describe("IResponse", () => {
it("should have the correct properties", () => {
const response: IResponse = {
incompleteResults: false,
items: [
{
id: 1,
name: "repo1",
fullName: "description1",
stargazersCount: 10,
owner : {
login: "login1",
},
},
],
totalCount: 1,
};

expect(response).toHaveProperty("incompleteResults");
expect(response).toHaveProperty("items");
expect(response.items).toBeInstanceOf(Array);
expect(response).toHaveProperty("totalCount");
});

it("should handle empty items array", () => {
const response: IResponse = {
incompleteResults: false,
items: [],
totalCount: 0,
};

expect(response.items).toHaveLength(0);
expect(response.totalCount).toBe(0);
});

it("should handle incompleteResults flag", () => {
const response: IResponse = {
incompleteResults: true,
items: [
{
id: 1,
name: "repo1",
fullName: "description1",
stargazersCount: 10,
owner : {
login: "login1",
}
},
],
totalCount: 100,
};

expect(response.incompleteResults).toBe(true);
expect(response.totalCount).toBeGreaterThan(response.items.length);
});
});
2 changes: 1 addition & 1 deletion src/utils/createEmotionCache.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import createCache from "@emotion/cache";

const isBrowser = typeof document !== "undefined";

// On the client side, Create a meta tag at the top of the <head> and set it as insertionPoint.
// This assures that MUI styles are loaded first.
// It allows developers to easily override MUI styles with other styling solutions, like CSS modules.
export default function createEmotionCache() {
let insertionPoint;
const isBrowser = typeof document !== "undefined";

if (isBrowser) {
const emotionInsertionPoint = document.querySelector<HTMLMetaElement>(
Expand Down
42 changes: 42 additions & 0 deletions src/utils/tests/createEmotionCache.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import createEmotionCache from "../createEmotionCache";

describe("createEmotionCache", () => {
let originalDocument;

beforeAll(() => {
originalDocument = global.document;
});

afterEach(() => {
global.document = originalDocument; // Restore the original document after each test
});

it("should create a cache object with the correct key", () => {
const cache = createEmotionCache();
expect(cache.key).toBe("mui-style");
});

it("should set insertionPoint to undefined when running on the server", () => {
global.document = undefined;
const cache = createEmotionCache();
expect(cache.sheet.insertionPoint).toBeUndefined();
});

it("should set insertionPoint to the emotion-insertion-point meta tag when running on the client", () => {
const emotionInsertionPoint = document.createElement("meta");
emotionInsertionPoint.name = "emotion-insertion-point";
document.head.appendChild(emotionInsertionPoint);

const cache = createEmotionCache();

expect(cache.sheet.insertionPoint).toBe(emotionInsertionPoint);

document.head.removeChild(emotionInsertionPoint);
});

it("should set insertionPoint to undefined when emotion-insertion-point meta tag is not found", () => {
global.document = {};
const cache = createEmotionCache();
expect(cache.sheet.insertionPoint).toBeUndefined();
});
});
62 changes: 32 additions & 30 deletions src/utils/tests/index.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,31 @@
import camelCase from "lodash/camelCase";
import { isLocal, mapKeysDeep, convertObjectToCamelCase } from "../index";



describe("Tests for mapKeysDeep function", () => {
let fn;
beforeAll(() => {
fn = keys => camelCase(keys);
});
it("should return something objet", () => {
const obj = {
locationone: "/route1",
locationtwo: "/route2",
locationthree: { locationone: "/route1", locationtwo: "/route2" },
};
expect(mapKeysDeep(obj, fn)).toEqual(obj);
});

it("should operate array accordingly", () => {
const arr = [{ locationone: "/route1", locationtwo: "/route2" }];
expect(mapKeysDeep(arr, fn)).toEqual(arr);
});

it("should return the passed value if its not an array or object", () => {
expect(mapKeysDeep("None", fn)).toEqual("None");
});
});
describe("Tests for isLocal method", () => {
const OLD_ENV = process.env;

Expand All @@ -26,37 +51,13 @@ describe("Tests for isLocal method", () => {
});
});

describe("Tests for mapKeysDeep method", () => {
let fn;
beforeAll(() => {
fn = keys => camelCase(keys);
});
it("should return something objet", () => {
const obj = {
locationone: "/route1",
locationtwo: "/route2",
locationthree: { locationone: "/route1", locationtwo: "/route2" },
};
expect(mapKeysDeep(obj, fn)).toEqual(obj);
});

it("should operate array accordingly", () => {
const arr = [{ locationone: "/route1", locationtwo: "/route2" }];
expect(mapKeysDeep(arr, fn)).toEqual(arr);
});

it("should return the passed value if its not an array or object", () => {
expect(mapKeysDeep(10, fn)).toEqual(10);
});
});

describe("Tests for convertObjectToCamelCase", () => {
it("should throw an error if incorrect type is provided", () => {
expect(() => {
// @ts-expect-error we are checking if it throws an error if an array is passed instead of an object
// this causes TypeScript to throw an error since it can't take an array
convertObjectToCamelCase(["hey"]);
}).toThrowError();
}).toThrow();
});

it("should convert the object's keys into camelCase", () => {
Expand All @@ -70,12 +71,13 @@ describe("Tests for convertObjectToCamelCase", () => {
another_camel: "statement",
};

convertObjectToCamelCase(snakeObject);
const returnCamelObject = convertObjectToCamelCase<typeof camelObject>(snakeObject);


const cKeys = Object.keys(camelObject);
const sKeys = Object.keys(snakeObject);
const rKeys = Object.keys(returnCamelObject);

expect(cKeys[0]).toEqual(sKeys[0]);
expect(cKeys[1]).toEqual(sKeys[1]);
expect(cKeys[0]).toEqual(rKeys[0]);
expect(cKeys[1]).toEqual(rKeys[1]);
});
});
});
Loading