diff --git a/__mocks__/fixtures/challenge.ts b/__mocks__/fixtures/challenge.ts index 9e3dd301d..6eede1843 100644 --- a/__mocks__/fixtures/challenge.ts +++ b/__mocks__/fixtures/challenge.ts @@ -116,18 +116,6 @@ export const submission: Submission = { }, }; -export const mockInvite = { - created_at: new Date().toISOString(), - id: "invite", - ref: "invitation ref", - status: "invitation status", - team_ref: "team reference", - timestamp: 3, - updated_at: new Date().toISOString(), - user: mockUser, - user_id: "user id", -}; - export const mockTeamMember: TeamMember = { created_at: new Date().toISOString(), id: "id", @@ -148,13 +136,25 @@ export const mockTeam: Team = { name: "Master", organizer: mockUser, organizer_id: "organizer id", - invites: [mockInvite], members: [mockTeamMember], ref: "", timestamp: "", updated_at: new Date().toISOString(), }; +export const mockInvite = { + created_at: new Date().toISOString(), + id: "invite", + ref: "invitation ref", + status: "invitation status", + team_ref: "team reference", + timestamp: 3, + updated_at: new Date().toISOString(), + user: mockUser, + user_id: "user id", + team: mockTeam, +}; + export const mockFeedback: Feedback = { submission: submission, id: "234-4231243", diff --git a/__mocks__/fixtures/reward.ts b/__mocks__/fixtures/reward.ts index d58818ed1..026787e9b 100644 --- a/__mocks__/fixtures/reward.ts +++ b/__mocks__/fixtures/reward.ts @@ -8,11 +8,12 @@ export const reward = { community: "community", token: "token", stable: false, + fiatCurrency: "USD", amount: 10, timestamp: 10, distribution: { first: 1, second: 2, - third: 3 - } -} + third: 3, + }, +}; diff --git a/__tests__/components/sections/bounties/Navigation.test.tsx b/__tests__/components/sections/bounties/Navigation.test.tsx index 9d457caec..18d12e61c 100644 --- a/__tests__/components/sections/bounties/Navigation.test.tsx +++ b/__tests__/components/sections/bounties/Navigation.test.tsx @@ -1,7 +1,7 @@ import "@testing-library/jest-dom"; import { screen } from "@testing-library/react"; import BountiesNavigation from "@/components/sections/bounties/Navigation"; -import { renderWithRedux } from "../../../../__mocks__/renderWithRedux"; +import { renderWithRedux } from "@__mocks__/renderWithRedux"; import { List } from "@/utilities/CommunityNavigation"; jest.mock("next/router", () => ({ diff --git a/__tests__/components/sections/challenges/Header.test.tsx b/__tests__/components/sections/challenges/Header.test.tsx new file mode 100644 index 000000000..f25d3a7f2 --- /dev/null +++ b/__tests__/components/sections/challenges/Header.test.tsx @@ -0,0 +1,20 @@ +import ChallengeHeader from "@/components/sections/challenges/Header"; +import "@testing-library/jest-dom"; +import { screen } from "@testing-library/react"; +import { renderWithRedux } from "@__mocks__/renderWithRedux"; +import { challenge, submission } from "@__mocks__/fixtures/challenge"; + +describe("ChallengeHeader", () => { + it("should render the ChallengeHeader", () => { + renderWithRedux(); + const challengeheader = screen.getByTestId("challengeHeaderId"); + expect(challengeheader).toBeInTheDocument(); + }); + + it("should render the challenge header with section", () => { + renderWithRedux(, { challenges: { current: challenge, list: [challenge], loading: false, submission: submission } }); + expect(screen.getByText("communities.challenge.title")).toBeInTheDocument(); + expect(screen.getByText(challenge.name)).toBeInTheDocument(); + expect(screen.getByText(challenge.description)).toBeInTheDocument(); + }); +}); diff --git a/__tests__/components/sections/challenges/Learning.test.tsx b/__tests__/components/sections/challenges/Learning.test.tsx new file mode 100644 index 000000000..922e938b9 --- /dev/null +++ b/__tests__/components/sections/challenges/Learning.test.tsx @@ -0,0 +1,43 @@ +import Learning from "@/components/sections/challenges/Learning"; +import "@testing-library/jest-dom"; +import { screen } from "@testing-library/react"; +import { renderWithRedux } from "@__mocks__/renderWithRedux"; +import { challenge, submission } from "@__mocks__/fixtures/challenge"; +import { mockCourse, mockLearningModule } from "@__mocks__/fixtures/course"; +import { mockCommunity } from "@__mocks__/fixtures/community"; + +describe("Learning", () => { + it("should render Learning", () => { + renderWithRedux(); + const learning = screen.getByTestId("learningId"); + expect(learning).toBeInTheDocument(); + expect(screen.getByText("communities.overview.challenge.learning.title")).toBeInTheDocument(); + }); + + it("should render with course cards when the challenge has them", () => { + const coursesArray = [mockCourse]; + renderWithRedux(, { + challenges: { current: challenge, list: [challenge], loading: false, submission: submission }, + }); + coursesArray.forEach((course) => { + const courseNameElement = screen.getByText(course.name); + const courseDescriptionElement = screen.getByText(course.description); + expect(courseNameElement).toBeInTheDocument(); + expect(courseDescriptionElement).toBeInTheDocument(); + expect(courseDescriptionElement).toHaveTextContent(course.description); + }); + }); + + it("should render with learning module card", () => { + const learningArray = [mockLearningModule]; + renderWithRedux(); + learningArray.forEach((learningModule) => { + const learningTitleElement = screen.getByText(learningModule.title); + const learningDescriptionElement = screen.getByText(learningModule.description); + expect(learningTitleElement).toBeInTheDocument(); + expect(learningTitleElement).toHaveTextContent(learningModule.title); + expect(learningDescriptionElement).toBeInTheDocument(); + expect(learningDescriptionElement).toHaveTextContent(learningModule.description); + }); + }); +}); diff --git a/__tests__/components/sections/challenges/Objectives.test.tsx b/__tests__/components/sections/challenges/Objectives.test.tsx new file mode 100644 index 000000000..e73c775c2 --- /dev/null +++ b/__tests__/components/sections/challenges/Objectives.test.tsx @@ -0,0 +1,49 @@ +import Objectives from "@/components/sections/challenges/Objectives"; +import "@testing-library/jest-dom"; +import { screen } from "@testing-library/react"; +import { renderWithRedux } from "@__mocks__/renderWithRedux"; +import DateManager from "@/utilities/DateManager"; +import { challenge, submission } from "@__mocks__/fixtures/challenge"; + +describe("Objectives", () => { + const challenges = challenge; + const submissions = submission; + const mockObjectivesStates = { challenges: { current: challenges, list: [challenges], loading: false, submission: submissions } }; + it("should render objectives", () => { + renderWithRedux(); + expect(screen.getByTestId("objectiveId")).toBeInTheDocument(); + expect(screen.getByText("communities.overview.challenge.objective.title")).toBeInTheDocument(); + }); + + it("should render the objective list", () => { + renderWithRedux(, mockObjectivesStates); + const objectiveValue = challenge.objectives.find((objective) => objective); + expect(screen.getByText(objectiveValue || "objectives 1")).toBeInTheDocument(); + }); + + it("should display challenge expiry date, when applicable", () => { + renderWithRedux(, mockObjectivesStates); + const expirationDate = challenge.expiresAt && DateManager.format(challenge.expiresAt, "MMMM d, yyyy", "en"); + if (expirationDate) { + const expirationDateElement = screen.getByText(expirationDate); + expect(expirationDateElement).toBeInTheDocument(); + expect(expirationDateElement).toHaveTextContent(expirationDate); + } + }); + + it("should display challenge hint", () => { + renderWithRedux(, { challenges: { current: challenges, list: [challenges], loading: false, submission: submissions } }); + const containsLink = new RegExp(/.*?<\/a>/g); + expect(containsLink.test('Example')).toBe(true); + expect(containsLink.test("This is a test string without a link.")).toBe(false); + expect(containsLink.test('Example')).toBe(false); + expect(containsLink.test('Nested')).toBe(true); + + expect(containsLink.test("
Not a link
")).toBe(false); + if (containsLink.test(challenge.hint as string)) { + expect(screen.getByText(challenge.hint as string)).toBeInTheDocument(); + } else { + expect(screen.getByText(challenge.hint)).toBeInTheDocument(); + } + }); +}); diff --git a/__tests__/components/sections/challenges/Rating.test.tsx b/__tests__/components/sections/challenges/Rating.test.tsx new file mode 100644 index 000000000..846dc9cdc --- /dev/null +++ b/__tests__/components/sections/challenges/Rating.test.tsx @@ -0,0 +1,48 @@ +import "@testing-library/jest-dom"; +import { screen } from "@testing-library/react"; +import { renderWithRedux } from "@__mocks__/renderWithRedux"; +import RubricRating from "@/components/sections/challenges/Rating"; +import type { RubricRatingProps } from "@/components/sections/challenges/Rating"; +import { mockCommunity } from "@__mocks__/fixtures/community"; +import { mockCourse } from "@__mocks__/fixtures/course"; +type MockRubricRating = Pick; + +const fixtureRubricRating: MockRubricRating = { + rubricRating: { + relevance: 2, + originality: 2, + quality: 8, + total: 12, + available: 2, + reward: 6, + rewardCoin: "ICP", + }, +}; +describe("RubricRating", () => { + const rubricRatings = fixtureRubricRating.rubricRating; + it("should render ratings with title", () => { + renderWithRedux(); + expect(screen.getByTestId("rubricRatingId")).toBeInTheDocument(); + expect(screen.getByTestId("coin")).toBeInTheDocument(); + expect(screen.getByText("communities.challenge.criteria.title")).toBeInTheDocument(); + }); + + it("should render ratings with rating criterias", () => { + renderWithRedux(, { + community: { current: mockCommunity, list: [mockCommunity], courses: [mockCourse], status: "succeeded", error: "error message" }, + }); + + mockCommunity.challenge?.ratingCriteria.forEach((criteria) => { + expect(screen.getByText(criteria.name)).toBeInTheDocument(); + expect(screen.getByText(criteria.name).textContent).toBe("rating criteria"); + criteria.rubric.forEach((rubric) => { + if (rubricRatings) { + if (rubricRatings[criteria.name] === rubric.points) { + expect(screen.getByText(rubric.points)).toBeInTheDocument(); + expect(screen.getByText(rubric.text)).toBeInTheDocument(); + } + } + }); + }); + }); +}); diff --git a/__tests__/components/sections/challenges/Rewards.test.tsx b/__tests__/components/sections/challenges/Rewards.test.tsx new file mode 100644 index 000000000..fc793efbc --- /dev/null +++ b/__tests__/components/sections/challenges/Rewards.test.tsx @@ -0,0 +1,32 @@ +import "@testing-library/jest-dom"; +import { screen } from "@testing-library/react"; +import { OverviewRewards } from "@/components/sections/challenges/Rewards"; +import { renderWithRedux } from "@__mocks__/renderWithRedux"; +import { challenge, submission } from "@__mocks__/fixtures/challenge"; + +jest.mock("next/router", () => ({ + useRouter: () => ({ + query: "query", + }), +})); + +describe("Reward", () => { + it("should render a reward", () => { + renderWithRedux(); + expect(screen.getByTestId("overviewRewardId")).toBeInTheDocument(); + }); + + it("should render reward with the challenge", () => { + renderWithRedux(, { challenges: { current: challenge, list: [challenge], loading: false, submission: submission } }); + if (challenge.rewards) { + challenge.rewards.forEach((reward) => { + expect(screen.getByText(`${reward.amount} ${reward.token}`)).toBeInTheDocument(); + }); + } + if (challenge.isHackathon) { + const challengeCertificate = screen.getByText("communities.overview.challenge.participate"); + expect(challengeCertificate).toBeInTheDocument(); + expect(challengeCertificate.textContent).toContain(challenge.reward?.token || challenge?.rewards[0]?.token || ""); + } + }); +}); diff --git a/__tests__/components/sections/challenges/Rubric.test.tsx b/__tests__/components/sections/challenges/Rubric.test.tsx new file mode 100644 index 000000000..79b1c19c3 --- /dev/null +++ b/__tests__/components/sections/challenges/Rubric.test.tsx @@ -0,0 +1,36 @@ +import "@testing-library/jest-dom"; +import { screen } from "@testing-library/react"; +import { renderWithRedux } from "@__mocks__/renderWithRedux"; +import RubricHeader from "@/components/sections/challenges/Rubric"; +import { challenge, submission } from "@__mocks__/fixtures/challenge"; +import { mockRatingCriteria, Rubric } from "@__mocks__/fixtures/course"; + +describe("Rubric", () => { + it("should render the Rubric header", () => { + renderWithRedux(); + expect(screen.getByTestId("rubricId")).toBeInTheDocument(); + }); + + it("should render the Rubric with ratings", () => { + renderWithRedux(, { + challenges: { current: challenge, list: [challenge], loading: false, submission: submission }, + }); + const rubricHeaderName = screen.getByText(mockRatingCriteria.name); + expect(rubricHeaderName).toBeInTheDocument(); + + const selectedRubric = (id: string) => [Rubric].find((rubric) => rubric.id === id); + + [mockRatingCriteria].forEach((criteria) => { + expect(screen.getByText(criteria.name)).toBeInTheDocument(); + criteria.rubric.forEach((rubric) => { + if (selectedRubric(rubric.id)) { + const rubricPoints = selectedRubric(rubric.id)?.points; + expect(screen.getByText(rubricPoints || "id")).toBeInTheDocument(); + } else { + expect(screen.getByText(rubric.points)).toBeInTheDocument(); + } + expect(screen.getByText(rubric.text)).toBeInTheDocument(); + }); + }); + }); +}); diff --git a/__tests__/components/sections/challenges/SetupTeamChallenge.test.tsx b/__tests__/components/sections/challenges/SetupTeamChallenge.test.tsx new file mode 100644 index 000000000..9780628b8 --- /dev/null +++ b/__tests__/components/sections/challenges/SetupTeamChallenge.test.tsx @@ -0,0 +1,35 @@ +import "@testing-library/jest-dom"; +import { screen } from "@testing-library/react"; +import SetupTeamChallenge from "@/components/sections/challenges/SetupTeamChallenge"; +import { renderWithRedux } from "@__mocks__/renderWithRedux"; +import { challenge, mockInvite, submission } from "@__mocks__/fixtures/challenge"; + +describe("SetUpTeamChallenge", () => { + const mockTeamChallengeStates = { + challenges: { current: challenge, list: [challenge], loading: false, submission: submission }, + invites: { data: mockInvite }, + }; + it("renders without crashing", () => { + renderWithRedux(); + expect(screen.getByTestId("challengeId")).toBeInTheDocument(); + }); + + it("renders content correctly", () => { + renderWithRedux(, mockTeamChallengeStates); + expect(screen.getByText("Submission")).toBeInTheDocument(); + expect(screen.getByText("communities.overview.challenge.team.setup.info")).toBeInTheDocument(); + expect(screen.getByText("Form your team")).toBeInTheDocument(); + expect(screen.getByText(challenge?.additionalInfo?.TEAM_FORMATION.text || " ") || "communities.overview.challenge.team.organization").toBeInTheDocument(); + }); + + it("renders the confirmation of the team invitation when there is an invite", () => { + renderWithRedux(, mockTeamChallengeStates); + if (!mockInvite.team.locked && mockInvite) { + expect(screen.getByText("Submit your team")).toBeInTheDocument(); + expect(screen.getByText(`The maximum team members for this challenge is ${challenge?.teamLimit} people`)).toBeInTheDocument(); + } else { + expect(screen.getByText("communities.overview.challenge.team.setup.submit-title")).toBeInTheDocument(); + expect(screen.getByText("communities.overview.challenge.team.setup.description")).toBeInTheDocument(); + } + }); +}); diff --git a/__tests__/components/sections/challenges/Submission.test.tsx b/__tests__/components/sections/challenges/Submission.test.tsx new file mode 100644 index 000000000..66736e16c --- /dev/null +++ b/__tests__/components/sections/challenges/Submission.test.tsx @@ -0,0 +1,49 @@ +import "@testing-library/jest-dom"; +import { screen } from "@testing-library/react"; +import Submission, { FormValues } from "@/components/sections/challenges/Submission"; +import { renderWithRedux } from "@__mocks__/renderWithRedux"; +import { FieldErrors } from "react-hook-form"; +import { challenge, mockTeam, submission } from "@__mocks__/fixtures/challenge"; +import { mockUser } from "@__mocks__/fixtures/user"; + +describe("Submission", () => { + let errors: FieldErrors; + const canSubmit = () => { + if (!challenge?.isTeamChallenge) return true; + return Boolean(!!mockTeam?.organizer); + }; + it("renders the submission section", async () => { + renderWithRedux(, { + challenges: { current: challenge, list: [challenge], loading: false, submission: submission }, + teams: { current: mockTeam, loading: true }, + }); + const submissionsClosed = challenge?.expiresAt ? Date.parse(challenge?.expiresAt) < Date.now() : false; + if (submissionsClosed) { + expect(screen.getByText("communities.overview.challenge.submissions-closed")).toBeInTheDocument(); + } else if (challenge.isTeamChallenge) { + expect(screen.getByText("communities.overview.challenge.submission.description")).toBeInTheDocument(); + } + }); + + it("validates submission form and displays necessary elements", () => { + renderWithRedux(, { + challenges: { current: challenge, list: [challenge], loading: false, submission: submission }, + teams: { current: mockTeam, loading: true }, + }); + if (!canSubmit()) { + expect(screen.getByText("communities.challenge.submission.hint")).toBeInTheDocument(); + } else { + expect(screen.getByTestId("submission-form")).toBeInTheDocument(); + if (challenge.format && mockUser && mockUser.avatar && challenge.format.githubLink && errors) { + expect(screen.getByText(mockTeam.organizer?.displayName || mockUser.displayName)).toBeInTheDocument(); + expect(screen.getByText(errors.text?.message as string)).toBeInTheDocument(); + expect(screen.getByText(errors.githubLink?.message as string)).toBeInTheDocument(); + } + expect(screen.getByText("Markdown")).toBeInTheDocument(); + if (challenge?.format.disclaimer) { + expect(screen.getByRole("checkbox")).toBeInTheDocument(); + } + expect(screen.getByText("submit")).toBeInTheDocument(); + } + }); +}); diff --git a/__tests__/components/sections/challenges/TeamChallenge.test.tsx b/__tests__/components/sections/challenges/TeamChallenge.test.tsx new file mode 100644 index 000000000..c52e6bb3b --- /dev/null +++ b/__tests__/components/sections/challenges/TeamChallenge.test.tsx @@ -0,0 +1,35 @@ +import "@testing-library/jest-dom"; +import { screen } from "@testing-library/react"; +import TeamChallenge, { hackathonChallengeSteps, teamChallengeSteps } from "@/components/sections/challenges/TeamChallenge"; +import { renderWithRedux } from "@__mocks__/renderWithRedux"; +import { challenge, submission } from "@__mocks__/fixtures/challenge"; + +interface CardData { + index: number; + title: string; + text: string; +} + +describe("TeamChallenge", () => { + const mockTeamChallengeStates = { + challenges: { current: challenge, list: [challenge], loading: false, submission: submission }, + }; + it("should render the team challenge section", () => { + renderWithRedux(, mockTeamChallengeStates); + expect(screen.getByText("Team Challenge")).toBeInTheDocument(); + expect(screen.getByText("To complete the team challenge, you need to follow these steps:")).toBeInTheDocument(); + }); + + it("should render all team challenge steps", () => { + renderWithRedux(, mockTeamChallengeStates); + let teamChallengeArray: CardData[] = []; + if (challenge.isHackathon) { + teamChallengeArray = hackathonChallengeSteps; + } else teamChallengeArray = teamChallengeSteps; + + teamChallengeArray.forEach((step) => { + expect(screen.getByText(step.text)).toBeInTheDocument(); + expect(screen.getByText(step.title)).toBeInTheDocument(); + }); + }); +}); diff --git a/__tests__/components/sections/challenges/_partials/HackathonPrize.test.tsx b/__tests__/components/sections/challenges/_partials/HackathonPrize.test.tsx new file mode 100644 index 000000000..8b4795e6f --- /dev/null +++ b/__tests__/components/sections/challenges/_partials/HackathonPrize.test.tsx @@ -0,0 +1,33 @@ +import HackathonPrize from "@/components/sections/challenges/_partials/HackathonPrize"; +import "@testing-library/jest-dom"; +import { render, screen } from "@testing-library/react"; +import { Distribution } from "@/types/course"; +import { reward } from "@__mocks__/fixtures/reward"; + +describe("HackathonPrize", () => { + const { first, second, third } = reward?.distribution || ({} as Distribution); + it("should render the hackathon prize", () => { + render(); + expect(screen.getByTestId("hackathonPrizeId")).toBeInTheDocument(); + }); + + it("should render hackathon prize with reward and description", () => { + render(); + if (reward.fiatCurrency) { + const currency = screen.getByText("communities.overview.reward.fiat.prize.pool"); + expect(currency).toBeInTheDocument(); + expect(currency.textContent).toBe("communities.overview.reward.fiat.prize.pool"); + } else { + const currency = screen.getByText("communities.overview.reward.crypto.prize.pool"); + expect(currency).toBeInTheDocument(); + expect(currency.textContent).toBe("communities.overview.reward.crypto.prize.pool"); + } + + const descriptionText = screen.getByText("Prize"); + expect(descriptionText).toBeInTheDocument(); + expect(descriptionText.textContent).toBe("Prize"); + + const distributionText = screen.getByText(`1st Place ${first}; 2nd Place ${second}; 3rd Place ${third}`); + expect(distributionText).toBeInTheDocument(); + }); +}); diff --git a/__tests__/components/sections/challenges/_partials/RewardsList.test.tsx b/__tests__/components/sections/challenges/_partials/RewardsList.test.tsx new file mode 100644 index 000000000..90d4c5728 --- /dev/null +++ b/__tests__/components/sections/challenges/_partials/RewardsList.test.tsx @@ -0,0 +1,16 @@ +import RewardsList from "@/components/sections/challenges/_partials/RewardsList"; +import { reward } from "@__mocks__/fixtures/reward"; +import "@testing-library/jest-dom"; +import { render, screen } from "@testing-library/react"; + +describe("RewardsList", () => { + it("should render the reward list", () => { + render(); + const rewardList = screen.getByTestId("rewardListId"); + expect(rewardList).toBeInTheDocument(); + [reward].forEach((reward) => { + expect(screen.getByText(reward.token)).toBeInTheDocument(); + expect(screen.getByText(reward.token).textContent).toBe("token"); + }); + }); +}); diff --git a/__tests__/components/sections/submissions/BestSubmission.test.tsx b/__tests__/components/sections/submissions/BestSubmission.test.tsx index 172ebfd43..a6d2047e0 100644 --- a/__tests__/components/sections/submissions/BestSubmission.test.tsx +++ b/__tests__/components/sections/submissions/BestSubmission.test.tsx @@ -1,7 +1,7 @@ import "@testing-library/jest-dom"; import { screen } from "@testing-library/react"; import { challenge, submission } from "@__mocks__/fixtures/challenge"; -import { renderWithRedux } from "../../../../__mocks__/renderWithRedux"; +import { renderWithRedux } from "@__mocks__/renderWithRedux"; import BestSubmissions from "@/components/sections/submissions/BestSubmissions"; jest.mock("next/router", () => ({ diff --git a/__tests__/components/ui/Avatar.test.tsx b/__tests__/components/ui/Avatar.test.tsx index 0037cd852..5a6f0011b 100644 --- a/__tests__/components/ui/Avatar.test.tsx +++ b/__tests__/components/ui/Avatar.test.tsx @@ -1,7 +1,7 @@ import Avatar from "@/components/ui/Avatar"; +import { mockProfile, userIcon } from "@__mocks__/fixtures/profile"; import "@testing-library/jest-dom"; import { render, screen } from "@testing-library/react"; -import { userIcon, mockProfile } from "../../../__mocks__/fixtures/profile"; describe("Avatar", () => { it("Should render the avatar", () => { diff --git a/__tests__/components/ui/Loader.test.tsx b/__tests__/components/ui/Loader.test.tsx index a0d5a15d7..0a53fb3eb 100644 --- a/__tests__/components/ui/Loader.test.tsx +++ b/__tests__/components/ui/Loader.test.tsx @@ -1,8 +1,8 @@ import Loader from "@/components/ui/Loader"; import "@testing-library/jest-dom"; import { screen } from "@testing-library/react"; -import { colors } from "../../../__mocks__/fixtures/colors"; -import { renderWithRedux } from "../../../__mocks__/renderWithRedux"; +import { colors } from "@__mocks__/fixtures/colors"; +import { renderWithRedux } from "@__mocks__/renderWithRedux"; jest.mock("next/router", () => ({ useRouter: () => ({ diff --git a/__tests__/components/ui/Reward.test.tsx b/__tests__/components/ui/Reward.test.tsx index d60311de2..b34f1d9f3 100644 --- a/__tests__/components/ui/Reward.test.tsx +++ b/__tests__/components/ui/Reward.test.tsx @@ -1,7 +1,7 @@ import OverviewRewards from "@/components/ui/Reward"; +import { reward } from "@__mocks__/fixtures/reward"; import "@testing-library/jest-dom"; import { render, screen } from "@testing-library/react"; -import { reward } from "../../../__mocks__/fixtures/reward"; describe("OverviewRewards", () => { it("Should render reward", () => { diff --git a/__tests__/components/ui/SideNavigation/_partials/SideNavLink.test.tsx b/__tests__/components/ui/SideNavigation/_partials/SideNavLink.test.tsx index c669c1af9..a4ad96f4d 100644 --- a/__tests__/components/ui/SideNavigation/_partials/SideNavLink.test.tsx +++ b/__tests__/components/ui/SideNavigation/_partials/SideNavLink.test.tsx @@ -1,8 +1,8 @@ import CourseLink from "@/components/ui/SideNavigation/_partials/SideNavLink"; import "@testing-library/jest-dom"; import { screen } from "@testing-library/react"; -import { renderWithRedux } from "../../../../../__mocks__/renderWithRedux"; -import { colors } from "../../../../../__mocks__/fixtures/colors"; +import { renderWithRedux } from "@__mocks__/renderWithRedux"; +import { colors } from "@__mocks__/fixtures/colors"; jest.mock("next/router", () => ({ useRouter: () => ({ @@ -29,6 +29,7 @@ describe("SideNavLink", () => { colors: colors, locked: false, showReferralPopup: false, + showJobOffersPopup: false, }, }); const courseLink = screen.getByTestId("courseLinkId"); diff --git a/__tests__/components/ui/SideNavigation/index.test.tsx b/__tests__/components/ui/SideNavigation/index.test.tsx index f68e1c53e..c3d5d2a39 100644 --- a/__tests__/components/ui/SideNavigation/index.test.tsx +++ b/__tests__/components/ui/SideNavigation/index.test.tsx @@ -1,10 +1,10 @@ import SideNavigation from "@/components/ui/SideNavigation"; import "@testing-library/jest-dom"; import { screen } from "@testing-library/react"; -import { colors } from "../../../../__mocks__/fixtures/colors"; +import { colors } from "@__mocks__/fixtures/colors"; import { Items } from "@/store/feature/communities/navigation.slice"; -import { renderWithRedux } from "../../../../__mocks__/renderWithRedux"; -import { mockItems } from "../../../../__mocks__/fixtures/menu"; +import { renderWithRedux } from "@__mocks__/renderWithRedux"; +import { mockItems } from "@__mocks__/fixtures/menu"; jest.mock("next/router", () => ({ useRouter: () => ({ @@ -27,8 +27,6 @@ const renderSideNavigation = (items: Items[] = []) => { }; describe("SideNavigation", () => { - - it("should render side navigation", () => { renderSideNavigation(); const sideNav = screen.getByTestId("sideNavId"); diff --git a/__tests__/components/ui/SocialLink.test.tsx b/__tests__/components/ui/SocialLink.test.tsx index 16c7bea49..ca178b340 100644 --- a/__tests__/components/ui/SocialLink.test.tsx +++ b/__tests__/components/ui/SocialLink.test.tsx @@ -1,7 +1,7 @@ import SocialLink from "@/components/ui/SocialLink"; import "@testing-library/jest-dom"; import { render, screen } from "@testing-library/react"; -import { link } from "../../../__mocks__/fixtures/link"; +import { link } from "@__mocks__/fixtures/link"; type LinkType = { url: string; diff --git a/__tests__/components/ui/Video.test.tsx b/__tests__/components/ui/Video.test.tsx index 05bc1947f..0a0969ae7 100644 --- a/__tests__/components/ui/Video.test.tsx +++ b/__tests__/components/ui/Video.test.tsx @@ -1,7 +1,7 @@ import Video from "@/components/ui/Video"; import "@testing-library/jest-dom"; import { render, screen } from "@testing-library/react"; -import { video } from "../../../__mocks__/fixtures/video"; +import { video } from "@__mocks__/fixtures/video"; describe("Video", () => { it("should render the video", () => { diff --git a/__tests__/components/ui/button/Arrow.test.tsx b/__tests__/components/ui/button/Arrow.test.tsx index 5414b5931..9656de380 100644 --- a/__tests__/components/ui/button/Arrow.test.tsx +++ b/__tests__/components/ui/button/Arrow.test.tsx @@ -1,7 +1,7 @@ import ArrowButton from "@/components/ui/button/Arrow"; import "@testing-library/jest-dom"; import { screen } from "@testing-library/react"; -import { renderWithRedux } from "../../../../__mocks__/renderWithRedux"; +import { renderWithRedux } from "@__mocks__/renderWithRedux"; jest.mock("next/router", () => ({ useRouter: () => ({ diff --git a/__tests__/components/ui/button/index.test.tsx b/__tests__/components/ui/button/index.test.tsx index 7601048e2..09dad4eeb 100644 --- a/__tests__/components/ui/button/index.test.tsx +++ b/__tests__/components/ui/button/index.test.tsx @@ -1,7 +1,7 @@ import "@testing-library/jest-dom"; import { fireEvent, screen } from "@testing-library/react"; import Button, { ButtonProps } from "@/components/ui/button"; -import { renderWithRedux } from "../../../../__mocks__/renderWithRedux"; +import { renderWithRedux } from "@__mocks__/renderWithRedux"; jest.mock("next/router", () => ({ useRouter: () => ({ diff --git a/src/components/sections/challenges/Header.tsx b/src/components/sections/challenges/Header.tsx index 12d9acdd8..bc9a7b808 100644 --- a/src/components/sections/challenges/Header.tsx +++ b/src/components/sections/challenges/Header.tsx @@ -4,6 +4,10 @@ import { useSelector } from "@/hooks/useTypedSelector"; import { useTranslation } from "next-i18next"; import { ReactElement } from "react"; +interface challengeHeaderProp { + testId?: string; +} + /** * Challenge header component * @date 4/18/2023 - 12:08:02 PM @@ -11,12 +15,12 @@ import { ReactElement } from "react"; * @export * @returns {ReactElement} */ -export default function ChallengeHeader(): ReactElement { +export default function ChallengeHeader({ testId = "challengeHeaderId" }: challengeHeaderProp): ReactElement { const { t } = useTranslation(); const challenge = useSelector((state) => state.challenges.current); return ( -
+
diff --git a/src/components/sections/challenges/Learning.tsx b/src/components/sections/challenges/Learning.tsx index 0c3e4be52..b3edc6b05 100644 --- a/src/components/sections/challenges/Learning.tsx +++ b/src/components/sections/challenges/Learning.tsx @@ -8,12 +8,19 @@ import { Community } from "@/types/community"; import { useSelector } from "@/hooks/useTypedSelector"; import { useTranslation } from "next-i18next"; +interface learningProps { + courses: Course[]; + learningModules: LearningModule[]; + community: Community; + testId?: string; +} + /** * Learning component. * * @returns {JSX.Element} The Learning component JSX element. */ -export default function Learning({ courses, learningModules, community }: { courses: Course[]; learningModules: LearningModule[]; community: Community }): JSX.Element { +export default function Learning({ courses, learningModules, community, testId = "learningId" }: learningProps): JSX.Element { const challenge = useSelector((state) => state.challenges.current); const { t } = useTranslation(); return ( @@ -24,7 +31,9 @@ export default function Learning({ courses, learningModules, community }: { cour isExpanded content={ <> -
{t("communities.overview.challenge.learning.title")}
+
+ {t("communities.overview.challenge.learning.title")} +
{courses?.map((course) => ( .*?<\/a>/g); @@ -23,7 +23,7 @@ export default function Objectives(): ReactElement { const expirationDate = challenge?.expiresAt && DateManager.format(challenge.expiresAt, "MMMM d, yyyy", "en"); return (
-
+
{expirationDate && } diff --git a/src/components/sections/challenges/Rating.tsx b/src/components/sections/challenges/Rating.tsx index 8a62981a2..e7327a019 100644 --- a/src/components/sections/challenges/Rating.tsx +++ b/src/components/sections/challenges/Rating.tsx @@ -20,7 +20,7 @@ interface RubricRatingMultiSelector { community: Community | null; colors: Colors; } -interface RubricRatingProps { +export interface RubricRatingProps { rubricRating?: { relevance: number; originality: number; @@ -32,6 +32,7 @@ interface RubricRatingProps { [key: string]: string | number; }; hideTitle?: boolean; + testId?: string; } /** @@ -64,6 +65,7 @@ export default function RubricRating({ rewardCoin: "CGLD", }, hideTitle = false, + testId, }: RubricRatingProps): ReactElement { const { t } = useTranslation(); @@ -108,7 +110,7 @@ export default function RubricRating({
))} -
+
{t("communities.challenge.rating.total")}
diff --git a/src/components/sections/challenges/Rewards.tsx b/src/components/sections/challenges/Rewards.tsx index adcbff865..458f23a91 100644 --- a/src/components/sections/challenges/Rewards.tsx +++ b/src/components/sections/challenges/Rewards.tsx @@ -6,6 +6,10 @@ import Certificate from "@/components/ui/Certificate"; import { useRouter } from "next/router"; import RewardCertificate from "@/components/cards/challenge/RewardCertificate"; +interface OverviewRewardsProps { + testId?: string; +} + /** * Overview reward section component * @date 4/18/2023 - 1:44:34 PM @@ -13,7 +17,7 @@ import RewardCertificate from "@/components/cards/challenge/RewardCertificate"; * @export * @returns {ReactElement} */ -export function OverviewRewards(): ReactElement { +export function OverviewRewards({ testId = "overviewRewardId" }: OverviewRewardsProps): ReactElement { const { t } = useTranslation(); const challenge = useSelector((state) => state.challenges.current); const router = useRouter(); @@ -21,7 +25,9 @@ export function OverviewRewards(): ReactElement { return (
-

{t("course.challenge.reward.certificate.description")}

+

+ {t("course.challenge.reward.certificate.description")} +

diff --git a/src/components/sections/challenges/Rubric.tsx b/src/components/sections/challenges/Rubric.tsx index b1353cd8a..fc7aa020d 100644 --- a/src/components/sections/challenges/Rubric.tsx +++ b/src/components/sections/challenges/Rubric.tsx @@ -22,6 +22,7 @@ interface RubricHeaderProps { ratingCriteria: RatingCriteria[]; selected: Rubric[]; hideTitle?: boolean; + testId?: string; } /** @@ -36,7 +37,7 @@ interface RubricHeaderProps { } * @returns {ReactElement} */ -export default function RubricHeader({ ratingCriteria, selected, hideTitle = false }: RubricHeaderProps): ReactElement { +export default function RubricHeader({ ratingCriteria, selected, hideTitle = false, testId }: RubricHeaderProps): ReactElement { const { t } = useTranslation(); const { challenge, colors } = useMultiSelector({ challenge: (state: IRootState) => state.challenges.current, @@ -57,7 +58,7 @@ export default function RubricHeader({ ratingCriteria, selected, hideTitle = fal const hackatonPassingScore = t("communities.challenge.hackathon.passing.score", { threshold: challenge?.threshold, prizePool: `USD ${reward?.amount}` }); return ( -
+
{challenge?.isHackathon ? (
) : ( diff --git a/src/components/sections/challenges/SetupTeamChallenge.tsx b/src/components/sections/challenges/SetupTeamChallenge.tsx index 71294f915..a34c8f851 100644 --- a/src/components/sections/challenges/SetupTeamChallenge.tsx +++ b/src/components/sections/challenges/SetupTeamChallenge.tsx @@ -18,14 +18,16 @@ interface Props { * * @returns {JSX.Element} The SetupTeamChallenge component JSX element. */ -export default function SetupTeamChallenge(): JSX.Element { +export default function SetupTeamChallenge({ testid }: { testid?: string }): JSX.Element { const { invite, challenge } = useMultiSelector({ invite: (state: IRootState) => state.invites.data, challenge: (state: IRootState) => state.challenges.current }); const { t } = useTranslation(); return (
-
{t("communities.overview.challenge.team.setup.info")}
+
+ {t("communities.overview.challenge.team.setup.info")} +
{invite && !invite.team?.locked ? ( diff --git a/src/components/sections/challenges/Submission.tsx b/src/components/sections/challenges/Submission.tsx index 5a4159456..add8199ce 100644 --- a/src/components/sections/challenges/Submission.tsx +++ b/src/components/sections/challenges/Submission.tsx @@ -35,7 +35,7 @@ interface SubmissionMultiSelector { currentSubmission: TSubmission; } -interface FormValues { +export interface FormValues { text: string; githubLink: string; } @@ -51,7 +51,7 @@ const isValid = (form: FormValues, challenge: Challenge | null) => { return challenge?.format.githubLink ? form.text.length > 0 && form.githubLink.length > 0 : form.text.length > 0; }; -export default function Submission(): ReactElement { +export default function Submission({testId}: {testId?: string}): ReactElement { const { watch, register, @@ -139,7 +139,7 @@ export default function Submission(): ReactElement { {!canSubmit ? ( {t("communities.challenge.submission.hint")} ) : ( -
+ {challenge?.format && (
diff --git a/src/components/sections/challenges/TeamChallenge.tsx b/src/components/sections/challenges/TeamChallenge.tsx index 9699cffef..d86463061 100644 --- a/src/components/sections/challenges/TeamChallenge.tsx +++ b/src/components/sections/challenges/TeamChallenge.tsx @@ -19,44 +19,44 @@ interface CardData { * * @interface TeamChallengeCard */ +export const hackathonChallengeSteps: CardData[] = [ + { + index: 1, + title: "Form your team", + text: "Open Telegram group and find your teammates to complete the challenge with you", + }, + { + index: 2, + title: "Confirm your team", + text: "Make sure your teammates accept notification to confirm your team", + }, + { + index: 3, + title: "Submit!", + text: "Once you have completed the challenge, only one person needs to submit it at the end of this page", + }, +]; +export const teamChallengeSteps: CardData[] = [ + { + index: 1, + title: "Form your team", + text: "Open discord channel #teams and find your teammates to complete the challenge with you", + }, + { + index: 2, + title: "Confirm your team", + text: "Make sure your teammates accept notification to confirm your team", + }, + { + index: 3, + title: "Submit!", + text: "Once you have completed the challenge, only one person needs to submit it at the end of this page", + }, +]; + export default function TeamChallenge(): JSX.Element { const challenge = useSelector((state) => state.challenges.current); - const hackathonChallengeSteps: CardData[] = [ - { - index: 1, - title: "Form your team", - text: "Open Telegram group and find your teammates to complete the challenge with you", - }, - { - index: 2, - title: "Confirm your team", - text: "Make sure your teammates accept notification to confirm your team", - }, - { - index: 3, - title: "Submit!", - text: "Once you have completed the challenge, only one person needs to submit it at the end of this page", - }, - ]; - const teamChallengeSteps: CardData[] = [ - { - index: 1, - title: "Form your team", - text: "Open discord channel #teams and find your teammates to complete the challenge with you", - }, - { - index: 2, - title: "Confirm your team", - text: "Make sure your teammates accept notification to confirm your team", - }, - { - index: 3, - title: "Submit!", - text: "Once you have completed the challenge, only one person needs to submit it at the end of this page", - }, - ]; - const steps: CardData[] = useMemo(() => { return challenge?.isHackathon ? hackathonChallengeSteps : teamChallengeSteps; }, [challenge?.isTeamChallenge]); diff --git a/src/components/sections/challenges/_partials/HackathonPrize.tsx b/src/components/sections/challenges/_partials/HackathonPrize.tsx index 35d8a12f4..99b748c52 100644 --- a/src/components/sections/challenges/_partials/HackathonPrize.tsx +++ b/src/components/sections/challenges/_partials/HackathonPrize.tsx @@ -2,13 +2,13 @@ import { Distribution, Reward } from "@/types/course"; import { shortenNumber } from "@/utilities"; import { useTranslation } from "react-i18next"; -export default function HackathonPrize({ reward, description }: { reward: Reward; description: string }) { +export default function HackathonPrize({ reward, description, testId }: { reward: Reward; description: string, testId?: string }) { const { t } = useTranslation() const { first, second, third } = reward?.distribution || ({} as Distribution); const amount = shortenNumber(reward?.amount); return ( <> -
+
{reward?.fiatCurrency ? t('communities.overview.reward.fiat.prize.pool', { amount, currency: reward.fiatCurrency, token: reward?.token }) : diff --git a/src/components/sections/challenges/_partials/RewardsList.tsx b/src/components/sections/challenges/_partials/RewardsList.tsx index c7dd17063..baacf0794 100644 --- a/src/components/sections/challenges/_partials/RewardsList.tsx +++ b/src/components/sections/challenges/_partials/RewardsList.tsx @@ -1,14 +1,19 @@ import Reward from "@/components/cards/challenge/_partials/Reward"; import { Reward as TReward } from "@/types/course"; -export default function RewardsList({ rewards }: { rewards?: TReward[] }) { +interface RewardListProps { + rewards?: TReward[]; + testId?: string; +} + +export default function RewardsList({ rewards, testId = "rewardListId" }: RewardListProps) { return ( - <> +
{rewards?.map((reward, i) => (
))} - +
); } diff --git a/src/components/ui/Certificate.tsx b/src/components/ui/Certificate.tsx index c38679334..ffe1019af 100644 --- a/src/components/ui/Certificate.tsx +++ b/src/components/ui/Certificate.tsx @@ -30,7 +30,7 @@ interface CertificateProps { * * @type {[]} */ -const certificates = [ +export const certificates = [ { name: "Celo", icon: ,