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

Adding Test in frontend components #1684

Closed
wants to merge 33 commits into from
Closed
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
1c86153
added jest setup
Claudio-code Jul 14, 2023
72e093c
Merge branch 'main' into add-frontend-test
Claudio-code Jul 14, 2023
6cd8a88
added tests in redirect component of login
Claudio-code Jul 16, 2023
e66345a
Merge branch 'main' into add-frontend-test
Claudio-code Jul 16, 2023
83f1ca0
added path configs in jest
Claudio-code Jul 18, 2023
b65a85e
added setup of header and search
Claudio-code Jul 18, 2023
cb166f6
Merge branch 'main' into add-frontend-test
Claudio-code Jul 18, 2023
cc3457f
Added test to log out
Claudio-code Jul 20, 2023
1cc6554
Fixed locks
Claudio-code Jul 20, 2023
322cd8a
Added idea folder
Claudio-code Jul 20, 2023
1af1595
Merge branch 'main' into add-frontend-test
Claudio-code Jul 20, 2023
62cc405
removed file
Claudio-code Jul 22, 2023
6de007d
removed duplicated code
Claudio-code Jul 22, 2023
7c88186
added front end tests in ci
Claudio-code Jul 25, 2023
22841d6
changed react-i18next to global mock
Claudio-code Jul 25, 2023
4568978
removed @ts-ignore
Claudio-code Jul 25, 2023
a3cfac6
changed errors test in ProviderLink component
Claudio-code Jul 25, 2023
1bf47c4
Merge branch 'main' into add-frontend-test
Claudio-code Jul 25, 2023
4f6fa13
Fixed yarn.locks
Claudio-code Jul 26, 2023
5ce453a
added test to user avatar and login button after logout
Claudio-code Jul 26, 2023
6fbea2e
Merge branch 'main' into add-frontend-test
Claudio-code Jul 26, 2023
07e4ecc
Merge branch 'main' into add-frontend-test
Claudio-code Jul 28, 2023
4093607
Merge branch 'main' into add-frontend-test
Claudio-code Jul 28, 2023
3d94d85
Merge branch 'main' into add-frontend-test
Claudio-code Jul 30, 2023
b2c0f28
Merge branch 'main' into add-frontend-test
Claudio-code Jul 31, 2023
1dfd10d
changed pipeline stage
Claudio-code Jul 31, 2023
8d77378
changed to test accessability too
Claudio-code Jul 31, 2023
5ed79c9
removed not used imports
Claudio-code Jul 31, 2023
11f81f3
Merge branch 'main' into add-frontend-test
Claudio-code Jul 31, 2023
8adf3a3
Merge branch 'main' into add-frontend-test
Claudio-code Jul 31, 2023
69e4ad2
Merge branch 'main' into add-frontend-test
Claudio-code Aug 2, 2023
c695175
Merge branch 'main' into add-frontend-test
Claudio-code Aug 2, 2023
d266fca
Merge branch 'flathub:main' into add-frontend-test
Claudio-code Aug 5, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/frontend_ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ jobs:
- name: Lint
run: yarn lint

- name: Unitary Tests
razzeee marked this conversation as resolved.
Show resolved Hide resolved
run: yarn test

- name: Build application
run: yarn build
env:
Expand Down
5 changes: 4 additions & 1 deletion frontend/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -112,4 +112,7 @@ public/sitemap.xml
# Sentry
.sentryclirc

flatpak.github.io
# Jetbrains
.idea

flatpak.github.io
71 changes: 71 additions & 0 deletions frontend/__tests__/components/layout/Header.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import { fireEvent, render, waitFor } from "@testing-library/react"
import Header from "../../../src/components/layout/Header"
import { UserState } from "../../../src/types/Login"
import { UserContext, UserDispatchContext } from "src/context/user-info"
import { translationMock } from "../../../jest.setup"

describe("Header tests", () => {
it("User logs out successfully", async () => {
const dispatchMock = jest.fn()
const userState: UserState = {
loading: false,
info: {
auths: {
github: {
avatar: "https://avatars.githubusercontent.com/u/27268838?s=200&v=4",
login: "devflat",
},
gitlab: undefined,
gnome: undefined,
kde: undefined,
},
"is-moderator": false,
"dev-flatpaks": [],
"owned-flatpaks": [],
displayname: "dev-flatpak",
"accepted-publisher-agreement-at": ""
},
}

translationMock.mockImplementation((args) => {
if (args === "user-avatar") {
return `${userState.info.displayname}'s avatar`
}
return args
})

const expectedUrlValue = "https://wiki.gnome.org"
global.fetch = jest.fn(() =>
Promise.resolve({
ok: true,
json: () => Promise.resolve({ url: expectedUrlValue }),
}),
) as jest.Mock

const { getByText, container } = render(
<>
<UserContext.Provider value={userState}>
<UserDispatchContext.Provider value={dispatchMock}>
<Header />
</UserDispatchContext.Provider>
</UserContext.Provider>
</>,
)

const userIconBeforeLogout = container.querySelector("img.rounded-full")
razzeee marked this conversation as resolved.
Show resolved Hide resolved
expect(userIconBeforeLogout).toBeInTheDocument()
expect(userIconBeforeLogout.alt).toContain(userState.info.displayname)

jest.replaceProperty(userState, "info", null)

await waitFor(() => {
Claudio-code marked this conversation as resolved.
Show resolved Hide resolved
fireEvent.click(getByText("open-user-menu"))
fireEvent.click(getByText("log-out"))
})

expect(userIconBeforeLogout).not.toBeInTheDocument()
expect(getByText("login")).toBeInTheDocument()
expect(dispatchMock).toHaveBeenCalledWith({ type: "loading" })
expect(dispatchMock).toHaveBeenCalledWith({ type: "logout" })
Claudio-code marked this conversation as resolved.
Show resolved Hide resolved
})
})
138 changes: 138 additions & 0 deletions frontend/__tests__/components/login/ProviderLink.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
import { render, fireEvent, waitFor } from "@testing-library/react"
import ProviderLink from "../../../src/components/login/ProviderLink"
import { LoginProvider } from "src/types/Login"
import React, { Dispatch } from "react"
import { toast } from "react-toastify"
import { translationMock } from "../../../jest.setup"

type Props = {
provider: LoginProvider
inACard?: boolean
}

const githubProvider: LoginProvider = {
method: "github",
name: "GitHub",
}
const githubProps: Props = {
inACard: true,
provider: githubProvider,
}

const useStateSpy = jest.spyOn(React, "useState")
const setStateMock = jest.fn()

useStateSpy.mockImplementation((init) => [init, setStateMock])
const useLocalStorageSpy = jest.spyOn(Storage.prototype, "setItem")

jest.mock("react-toastify", () => ({
toast: {
success: jest.fn(),
error: jest.fn(),
},
}))

let location: Location
beforeEach(() => {
location = window.location
jest.spyOn(window, "location", "get").mockRestore()
const mockedLocation = {
...location,
}
jest.spyOn(window, "location", "get").mockReturnValue(mockedLocation)
})

describe("ProviderLink tests", () => {
it("redirect login with success", async () => {
const expectedRedirectValue = "https://wiki.gnome.org"
const expectedReturnToValue = '""'

global.fetch = jest.fn(() =>
Promise.resolve({
ok: true,
json: () => Promise.resolve({ redirect: expectedRedirectValue }),
}),
) as jest.Mock

const { getByRole } = render(
<ProviderLink
provider={githubProps.provider}
inACard={githubProps.inACard}
/>,
)

await waitFor(() => {
fireEvent.click(getByRole("button"))
})

expect(translationMock.mock.calls[0]).toEqual([
"login-with-provider",
{ provider: "GitHub" },
])
expect(setStateMock).toHaveBeenCalledWith(true)
expect(useLocalStorageSpy).toHaveBeenCalledWith(
"returnTo",
expectedReturnToValue,
)
expect(window.location.href).toEqual(expectedRedirectValue)
})

it("redirect login with api error", async () => {
global.fetch = jest.fn(() => Promise.reject()) as jest.Mock
const { getByRole } = render(
<ProviderLink
provider={githubProps.provider}
inACard={githubProps.inACard}
/>,
)

await waitFor(() => {
fireEvent.click(getByRole("button"))
})

expect(translationMock).toHaveBeenCalledWith("network-error-try-again")
})

it("redirect login with response error", async () => {
global.fetch = jest.fn(() =>
Promise.resolve({
ok: false,
json: () => Promise.resolve({}),
status: 404,
statusText: "Not Found",
}),
) as jest.Mock

const { getByRole } = render(
<ProviderLink
provider={githubProps.provider}
inACard={githubProps.inACard}
/>,
)

await waitFor(() => {
fireEvent.click(getByRole("button"))
})

expect(toast.error).toHaveBeenCalledWith("404 Not Found")
})

it("redirect login test if clicked is true not call api", async () => {
global.fetch = jest.fn() as jest.Mock
useStateSpy.mockImplementation(() => [true, setStateMock])
const { getByRole } = render(
<ProviderLink
provider={githubProps.provider}
inACard={githubProps.inACard}
/>,
)

await waitFor(() => {
fireEvent.click(getByRole("button"))
fireEvent.click(getByRole("button"))
fireEvent.click(getByRole("button"))
})
expect(global.fetch).not.toHaveBeenCalled()
expect(setStateMock).not.toHaveBeenCalled()
})
})
32 changes: 32 additions & 0 deletions frontend/jest.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import nextJest from "next/jest.js"

const createJestConfig = nextJest({
// Provide the path to your Next.js app to load next.config.js and .env files in your test environment
dir: "./",
})

// Add any custom config to be passed to Jest
/** @type {import('jest').Config} */
const config = {
rootDir: ".",
moduleNameMapper: {
"src/hooks/useWindowSize": "<rootDir>/src/hooks/useWindowSize",
"src/asyncs/login": "<rootDir>/src/asyncs/login",
"src/verificationProvider": "<rootDir>/src/verificationProvider",
"pages/apps/search": "<rootDir>/pages/apps/search",
"src/components/Spinner": "<rootDir>/src/components/Spinner",
"src/meilisearch": "<rootDir>/src/meilisearch",
"src/components/application/ApplicationCard":
"<rootDir>/src/components/application/ApplicationCard",
"src/types/Category": "<rootDir>/src/types/Category",
"src/components/Button": "<rootDir>/src/components/Button",
"src/context/user-info": "<rootDir>/src/context/user-info",
},
// Add more setup options before each test is run
setupFilesAfterEnv: ["<rootDir>/jest.setup.js"],
testMatch: ["**/__tests__/**/*.[jt]s?(x)", "**/?(*.)+(spec|test).[jt]s?(x)"],
testEnvironment: "jest-environment-jsdom",
}

// createJestConfig is exported this way to ensure that next/jest can load the Next.js config which is async
export default createJestConfig(config)
39 changes: 39 additions & 0 deletions frontend/jest.setup.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import "@testing-library/jest-dom/extend-expect"

afterEach(() => {
jest.clearAllMocks()
})

jest.mock("next/router", () => ({
useRouter() {
return {
route: "/",
pathname: "",
query: "",
asPath: "",
push: jest.fn(),
events: {
on: jest.fn(),
off: jest.fn(),
},
beforePopState: jest.fn(() => null),
prefetch: jest.fn(() => null),
}
},
}))

const translationMock = jest.fn()

jest.mock("react-i18next", () => ({
useTranslation: () => {
return {
t: translationMock,
i18n: {
changeLanguage: () => new Promise(() => {}),
dir: jest.fn(),
},
}
},
}))

export { translationMock }
9 changes: 7 additions & 2 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@
"storybook": "storybook dev -p 6006",
"build-storybook": "storybook build",
"postbuild": "next-sitemap",
"update-setup-instructions": "./setup-instructions.sh"
"update-setup-instructions": "./setup-instructions.sh",
"test": "jest"
},
"dependencies": {
"@collapsed/react": "^4.0.1",
Expand Down Expand Up @@ -61,13 +62,17 @@
"@storybook/react": "^7.0.26",
"@storybook/testing-library": "^0.2.0",
"@tailwindcss/typography": "^0.5.9",
"@testing-library/jest-dom": "^5.16.5",
"@testing-library/react": "^14.0.0",
"@types/node": "^20.4.1",
"@types/react": "^17.0.43",
"autoprefixer": "^10.4.14",
"eslint": "^8.44.0",
"eslint-config-next": "^13.4.9",
"eslint-config-prettier": "^8.8.0",
"eslint-plugin-prettier": "^4.2.1",
"jest": "^29.6.1",
"jest-environment-jsdom": "^29.6.1",
"postcss": "^8.4.25",
"prettier": "^2.8.8",
"prettier-plugin-tailwindcss": "^0.4.1",
Expand All @@ -76,4 +81,4 @@
"tailwindcss": "^3.3.2",
"typescript": "^5.1.6"
}
}
}