From 50c120400ce44197c595d4a8ae778aaa7864c56e Mon Sep 17 00:00:00 2001 From: Bryan Jennings Date: Sun, 18 Sep 2022 03:54:15 -0700 Subject: [PATCH 1/7] Add ExerciseCard to DOJO exercises page --- components/ExerciseCard/ExerciseCard.tsx | 2 +- pages/exercises/[lessonSlug].tsx | 142 ++++++++++++++++++++++- 2 files changed, 139 insertions(+), 5 deletions(-) diff --git a/components/ExerciseCard/ExerciseCard.tsx b/components/ExerciseCard/ExerciseCard.tsx index b53c23ab3..7631acf60 100644 --- a/components/ExerciseCard/ExerciseCard.tsx +++ b/components/ExerciseCard/ExerciseCard.tsx @@ -21,7 +21,7 @@ const ExerciseCard = ({ const [answerShown, setAnswerShown] = useState(false) return ( -
+
Problem
{problem}
diff --git a/pages/exercises/[lessonSlug].tsx b/pages/exercises/[lessonSlug].tsx index 78fad17ce..49921d2da 100644 --- a/pages/exercises/[lessonSlug].tsx +++ b/pages/exercises/[lessonSlug].tsx @@ -1,5 +1,5 @@ import { useRouter } from 'next/router' -import React from 'react' +import React, { useState } from 'react' import Layout from '../../components/Layout' import withQueryLoader, { QueryDataProps @@ -13,20 +13,55 @@ import NavCard from '../../components/NavCard' import ExercisePreviewCard, { ExercisePreviewCardProps } from '../../components/ExercisePreviewCard' +import { NewButton } from '../../components/theme/Button' +import ExerciseCard, { ExerciseCardProps } from '../../components/ExerciseCard' +import { ArrowLeftIcon } from '@primer/octicons-react' +import { Text } from '../../components/theme/Text' const exampleProblem = `const a = 5 a = a + 10 // what is a?` +const exampleProblem2 = `let a = 5 +a = a + 10 +// what is a?` + +const exampleProblem3 = `let a = 5 +a = a + '10' +// what is a?` + const mockExercisePreviews: ExercisePreviewCardProps[] = [ { moduleName: 'Variables', state: 'ANSWERED', problem: exampleProblem }, { moduleName: 'Variables', state: 'NOT ANSWERED', problem: exampleProblem }, { moduleName: 'Variables', state: 'ANSWERED', problem: exampleProblem } ] +const mockExercises: ExerciseCardProps[] = [ + { + challengeName: 'Variable mutation', + problem: exampleProblem, + answer: 'An error is thrown', + explanation: 'You cannot reassign variables that were created with "const".' + }, + { + challengeName: 'Variable mutation 2', + problem: exampleProblem2, + answer: '15', + explanation: 'You can reassign variables that were created with "let".' + }, + { + challengeName: 'Variable mutation 3', + problem: exampleProblem3, + answer: `'510'`, + explanation: + 'If you add a string and number together, the number gets converted to a string and then they get concatenated.' + } +] + const Exercises: React.FC> = ({ queryData }) => { const { lessons, alerts } = queryData const router = useRouter() + const [exerciseIndex, setExerciseIndex] = useState(-1) if (!router.isReady) return const slug = router.query.lessonSlug as string @@ -45,14 +80,113 @@ const Exercises: React.FC> = ({ queryData }) => { { text: 'exercises', url: `/exercises/${currentLesson.slug}` } ] + const exercise = mockExercises[exerciseIndex] + return ( + {exercise ? ( + 0} + showSkipButton={exerciseIndex < mockExercises.length - 1} + /> + ) : ( + + )} + {alerts && } + + ) +} + +type ExerciseProps = { + exercise: ExerciseCardProps + setExerciseIndex: React.Dispatch> + lessonTitle: string + showPreviousButton: boolean + showSkipButton: boolean +} + +const Exercise = ({ + exercise, + setExerciseIndex, + lessonTitle, + showPreviousButton, + showSkipButton +}: ExerciseProps) => { + return ( +
+ + +

{lessonTitle}

+ +
+ {showPreviousButton ? ( + + ) : ( +
+ )} + {showSkipButton ? ( + + ) : ( +
+ )} +
+
+ ) +} + +type ExerciseListProps = { + tabs: { text: string; url: string }[] + setExerciseIndex: React.Dispatch> + lessonTitle: string +} + +const ExerciseList = ({ + tabs, + setExerciseIndex, + lessonTitle +}: ExerciseListProps) => { + return ( + <> tab.text === 'exercises')} tabs={tabs} /> -

{currentLesson.title}

- {alerts && } +
+

{lessonTitle}

+ setExerciseIndex(0)}> + SOLVE EXERCISES + +
{mockExercisePreviews.map((exercisePreview, i) => ( @@ -68,7 +202,7 @@ const Exercises: React.FC> = ({ queryData }) => { ))}
- + ) } From b067a8ec6c77b324bf4cd76f6e71332fff050e98 Mon Sep 17 00:00:00 2001 From: Bryan Jennings Date: Sun, 18 Sep 2022 03:59:58 -0700 Subject: [PATCH 2/7] Update snapshot --- __tests__/__snapshots__/storyshots.test.js.snap | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/__tests__/__snapshots__/storyshots.test.js.snap b/__tests__/__snapshots__/storyshots.test.js.snap index 1961156da..12c2e74c9 100644 --- a/__tests__/__snapshots__/storyshots.test.js.snap +++ b/__tests__/__snapshots__/storyshots.test.js.snap @@ -5219,7 +5219,7 @@ Array [ exports[`Storyshots Components/ExerciseCard Basic 1`] = `
Date: Sun, 18 Sep 2022 04:20:15 -0700 Subject: [PATCH 3/7] Add tests for the DOJO exercise skip, previous, and exit buttons --- .../pages/exercises/[lessonSlug].test.js | 52 ++++++++++++++++++- 1 file changed, 51 insertions(+), 1 deletion(-) diff --git a/__tests__/pages/exercises/[lessonSlug].test.js b/__tests__/pages/exercises/[lessonSlug].test.js index c309ff611..e6f8a0fa4 100644 --- a/__tests__/pages/exercises/[lessonSlug].test.js +++ b/__tests__/pages/exercises/[lessonSlug].test.js @@ -1,5 +1,5 @@ import React from 'react' -import { render, waitFor, screen } from '@testing-library/react' +import { render, waitFor, screen, fireEvent } from '@testing-library/react' import '@testing-library/jest-dom' import Exercises from '../../../pages/exercises/[lessonSlug]' import { useRouter } from 'next/router' @@ -48,6 +48,56 @@ describe('Exercises page', () => { screen.getByRole('link', { name: 'LESSONS' }) }) + test('Renders exercise card with the skip, previous, and exit buttons', async () => { + const mocks = [ + { + request: { query: GET_APP }, + result: { + data: { + session, + lessons: dummyLessonData, + alerts: dummyAlertData + } + } + } + ] + + const { getByRole, queryByRole } = render( + + + + ) + + await waitFor(() => + getByRole('heading', { name: /Foundations of JavaScript/i }) + ) + + const solveExercisesButton = getByRole('button', { + name: 'SOLVE EXERCISES' + }) + fireEvent.click(solveExercisesButton) + + // Previous button is not in the document on the first exercise. + expect(queryByRole('button', { name: 'PREVIOUS' })).not.toBeInTheDocument() + + const skipButton = getByRole('button', { name: 'SKIP' }) + fireEvent.click(skipButton) + expect(queryByRole('button', { name: 'PREVIOUS' })).toBeInTheDocument() + + fireEvent.click(skipButton) + // Skip button should not be in the document because we're on the last exercise now. + expect(queryByRole('button', { name: 'SKIP' })).not.toBeInTheDocument() + + const previousButton = getByRole('button', { name: 'PREVIOUS' }) + fireEvent.click(previousButton) + expect(queryByRole('button', { name: 'SKIP' })).toBeInTheDocument() + + const exitButton = getByRole('button', { name: 'Exit' }) + fireEvent.click(exitButton) + expect(queryByRole('button', { name: 'PREVIOUS' })).not.toBeInTheDocument() + expect(queryByRole('button', { name: 'SKIP' })).not.toBeInTheDocument() + }) + test('Should not render lessons nav card tab if lesson docUrl is null', async () => { const mocks = [ { From 4841f3115c87ddfb7c109157e19a4f362d4410a1 Mon Sep 17 00:00:00 2001 From: Bryan Jennings Date: Sun, 18 Sep 2022 09:14:43 -0700 Subject: [PATCH 4/7] Move exercise card exit button text to aria-label --- pages/exercises/[lessonSlug].tsx | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/pages/exercises/[lessonSlug].tsx b/pages/exercises/[lessonSlug].tsx index 49921d2da..fe92abe77 100644 --- a/pages/exercises/[lessonSlug].tsx +++ b/pages/exercises/[lessonSlug].tsx @@ -61,7 +61,7 @@ const mockExercises: ExerciseCardProps[] = [ const Exercises: React.FC> = ({ queryData }) => { const { lessons, alerts } = queryData const router = useRouter() - const [exerciseIndex, setExerciseIndex] = useState(-1) + const [exerciseIndex, setExerciseIndex] = useState(-1) if (!router.isReady) return const slug = router.query.lessonSlug as string @@ -125,10 +125,7 @@ const Exercise = ({ className="btn ps-0 d-flex align-items-center" onClick={() => setExerciseIndex(-1)} > - -
- Exit -
+

{lessonTitle}

From 5b16eb695489e90b91eadc5c1737e4013b183324 Mon Sep 17 00:00:00 2001 From: Bryan Jennings Date: Sun, 18 Sep 2022 09:22:29 -0700 Subject: [PATCH 5/7] Remove unused import --- pages/exercises/[lessonSlug].tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/pages/exercises/[lessonSlug].tsx b/pages/exercises/[lessonSlug].tsx index fe92abe77..fc440d87b 100644 --- a/pages/exercises/[lessonSlug].tsx +++ b/pages/exercises/[lessonSlug].tsx @@ -16,7 +16,6 @@ import ExercisePreviewCard, { import { NewButton } from '../../components/theme/Button' import ExerciseCard, { ExerciseCardProps } from '../../components/ExerciseCard' import { ArrowLeftIcon } from '@primer/octicons-react' -import { Text } from '../../components/theme/Text' const exampleProblem = `const a = 5 a = a + 10 From 25681252eeead6a0560456453383ce3e437fcb4b Mon Sep 17 00:00:00 2001 From: Bryan Jennings Date: Sun, 18 Sep 2022 09:48:19 -0700 Subject: [PATCH 6/7] Add extra spacing between the nav card and header --- pages/exercises/[lessonSlug].tsx | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/pages/exercises/[lessonSlug].tsx b/pages/exercises/[lessonSlug].tsx index fc440d87b..af3ff258b 100644 --- a/pages/exercises/[lessonSlug].tsx +++ b/pages/exercises/[lessonSlug].tsx @@ -173,12 +173,14 @@ const ExerciseList = ({ }: ExerciseListProps) => { return ( <> - tab.text === 'exercises')} - tabs={tabs} - /> +
+ tab.text === 'exercises')} + tabs={tabs} + /> +
-

{lessonTitle}

+

{lessonTitle}

setExerciseIndex(0)}> SOLVE EXERCISES From b68ea19bace64c508b55e49803a7a7b6ef8cc684 Mon Sep 17 00:00:00 2001 From: Bryan Jennings Date: Sun, 18 Sep 2022 10:11:22 -0700 Subject: [PATCH 7/7] Style exercise skip and previous buttons --- pages/exercises/[lessonSlug].tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/pages/exercises/[lessonSlug].tsx b/pages/exercises/[lessonSlug].tsx index af3ff258b..982e561a7 100644 --- a/pages/exercises/[lessonSlug].tsx +++ b/pages/exercises/[lessonSlug].tsx @@ -138,7 +138,8 @@ const Exercise = ({ {showPreviousButton ? ( @@ -148,7 +149,8 @@ const Exercise = ({ {showSkipButton ? (