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: Create Exercise card #1998

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
7c63535
feat: Create AdminLessonExerciseCard component
flacial Jun 19, 2022
a7f30ee
test: Update snapshot
flacial Jun 19, 2022
40f881c
Merge remote-tracking branch 'upstream/master' into 2/1990-dojoadmin-…
flacial Jun 19, 2022
b4b9dfc
test: Update snapshot
flacial Jun 19, 2022
7207153
Merge branch 'master' into 2/1990-dojoadmin-create-exercises-tab
flacial Jun 20, 2022
77b659a
Merge branch 'master' into 2/1990-dojoadmin-create-exercises-tab
flacial Jun 21, 2022
5545784
Merge branch 'master' into 2/1990-dojoadmin-create-exercises-tab
flacial Jun 23, 2022
ee23de2
Merge branch 'master' into 2/1990-dojoadmin-create-exercises-tab
flacial Jun 23, 2022
909291a
feat(queries): Create updateExercise
flacial Jun 23, 2022
d59f096
feat: Add unflag functionality
flacial Jun 23, 2022
248004f
test: Update snapshots
flacial Jun 23, 2022
8786cec
feat: Add badge to card
flacial Jun 24, 2022
9d7191e
test: Update snapshots
flacial Jun 24, 2022
22cea7a
Merge remote-tracking branch 'upstream/master' into 2/1990-dojoadmin-…
flacial Jun 24, 2022
0dcb4ca
fix: Resolve conflict
flacial Jun 27, 2022
b7ebe84
Merge branch 'master' into 2/1990-dojoadmin-create-exercises-tab
flacial Jun 27, 2022
85c745c
Merge branch 'master' into 2/1990-dojoadmin-create-exercises-tab
flacial Jun 29, 2022
302f586
feat: Add copy button to contact
flacial Jun 29, 2022
d2212db
feat: Use useRemoveExerciseFlag hook
flacial Jun 29, 2022
31463da
test: Update snapshots
flacial Jun 29, 2022
08a810d
Revert "feat(queries): Create updateExercise"
flacial Jun 29, 2022
c894371
refactor: Get prev state from setState
flacial Jun 30, 2022
00c6a9d
refactor: Update assertion with a descriptive method
flacial Jun 30, 2022
f23ec24
Merge branch 'master' into 2/1990-dojoadmin-create-exercises-tab
flacial Jun 30, 2022
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
189 changes: 189 additions & 0 deletions __tests__/__snapshots__/storyshots.test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,195 @@ exports[`Storyshots Components/AdminLessonCard Basic 1`] = `
</div>
`;

exports[`Storyshots Components/AdminLessonExerciseCard Basic 1`] = `
<div
className="card"
>
<div
className="card__header"
>
<div
className="card__badges"
>
<span
className="card__header__badge card__header__badge__flagged"
>
FLAGGED
</span>
<span
className="card__header__badge card__header__badge__module"
>
VARIABLES
</span>
</div>
<p
className="card__header__username"
>
noob
</p>
<div
className="card__header__contact__container"
>
<div
className="card__header__contact"
>
<span>
[email protected]
</span>
<button
className="btn borderless btn-outline-primary btn-outline-bg-primary"
onClick={[Function]}
style={
Object {
"color": "primary",
}
}
>
<svg
aria-hidden="true"
className="octicon octicon-copy"
dangerouslySetInnerHTML={
Object {
"__html": "<path fill-rule=\\"evenodd\\" d=\\"M0 6.75C0 5.784.784 5 1.75 5h1.5a.75.75 0 010 1.5h-1.5a.25.25 0 00-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 00.25-.25v-1.5a.75.75 0 011.5 0v1.5A1.75 1.75 0 019.25 16h-7.5A1.75 1.75 0 010 14.25v-7.5z\\"></path><path fill-rule=\\"evenodd\\" d=\\"M5 1.75C5 .784 5.784 0 6.75 0h7.5C15.216 0 16 .784 16 1.75v7.5A1.75 1.75 0 0114.25 11h-7.5A1.75 1.75 0 015 9.25v-7.5zm1.75-.25a.25.25 0 00-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 00.25-.25v-7.5a.25.25 0 00-.25-.25h-7.5z\\"></path>",
}
}
fill="currentColor"
height={16}
role="img"
style={
Object {
"display": "inline-block",
"overflow": "visible",
"userSelect": "none",
"verticalAlign": "text-bottom",
}
}
viewBox="0 0 16 16"
width={16}
/>
</button>
</div>
<div
className="card__header__contact"
>
<span>
noob#123
</span>
<button
className="btn borderless btn-outline-primary btn-outline-bg-primary"
onClick={[Function]}
style={
Object {
"color": "primary",
}
}
>
<svg
aria-hidden="true"
className="octicon octicon-copy"
dangerouslySetInnerHTML={
Object {
"__html": "<path fill-rule=\\"evenodd\\" d=\\"M0 6.75C0 5.784.784 5 1.75 5h1.5a.75.75 0 010 1.5h-1.5a.25.25 0 00-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 00.25-.25v-1.5a.75.75 0 011.5 0v1.5A1.75 1.75 0 019.25 16h-7.5A1.75 1.75 0 010 14.25v-7.5z\\"></path><path fill-rule=\\"evenodd\\" d=\\"M5 1.75C5 .784 5.784 0 6.75 0h7.5C15.216 0 16 .784 16 1.75v7.5A1.75 1.75 0 0114.25 11h-7.5A1.75 1.75 0 015 9.25v-7.5zm1.75-.25a.25.25 0 00-.25.25v7.5c0 .138.112.25.25.25h7.5a.25.25 0 00.25-.25v-7.5a.25.25 0 00-.25-.25h-7.5z\\"></path>",
}
}
fill="currentColor"
height={16}
role="img"
style={
Object {
"display": "inline-block",
"overflow": "visible",
"userSelect": "none",
"verticalAlign": "text-bottom",
}
}
viewBox="0 0 16 16"
width={16}
/>
</button>
</div>
</div>
</div>
<div
className="card__section"
>
<h3
className="card__section__header"
>
Description
</h3>
<p
className="card__section__desc"
>
It’s all about context. The reason you get the above error is because, when you invoke setTimeout(), you are actually invoking window.setTimeout(). As a result, the anonymous function being passed to setTimeout()
</p>
</div>
<div
className="card__section"
>
<h3
className="card__section__header"
>
Answer
</h3>
<p
className="card__section__desc"
>
The right answer is setTimeout
</p>
<button
className="card__section--explanation"
onClick={[Function]}
>
Show
explanation
</button>
<div
aria-expanded={null}
className="card__section__explanation collapse"
id="explanation-collapse-text"
>
It's setTimeout because it's an async function and not sync
</div>
</div>
<div
className="card__section"
>
<h3
className="card__section__header"
>
Reason for flag
</h3>
<p
className="card__section__desc"
>
setTimeout takes a callback function and not a number
</p>
</div>
<div
className="card__footer"
>
<button
className="card__footer__btn"
disabled={false}
onClick={[Function]}
>
<span>
REMOVE EXERCISE
</span>
</button>
<button
className="card__footer__btn"
onClick={[Function]}
>
<span>
UNFLAG EXERCISE
</span>
</button>
</div>
</div>
`;

exports[`Storyshots Components/AdminLessonNav Basic 1`] = `
<div>
<div
Expand Down
190 changes: 190 additions & 0 deletions components/admin/lessons/AdminLessonExerciseCard.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
import React from 'react'
import Component from './AdminLessonExerciseCard'
import userEvent from '@testing-library/user-event'
import { render, screen } from '@testing-library/react'
import { MockedProvider } from '@apollo/client/testing'
import DELETE_EXERCISE from '../../../graphql/queries/deleteExercise'
import REMOVE_EXERCISE_FLAG from '../../../graphql/queries/removeExerciseFlag'

// Imported to be able to use expect(...).toBeInTheDocument()
import '@testing-library/jest-dom'

const user = {
username: 'noob',
discordUsername: 'noob#123',
email: '[email protected]'
}

const exercise = {
id: 1,
description:
'It’s all about context. The reason you get the above error is because, when you invoke setTimeout(), you are actually invoking window.setTimeout(). As a result, the anonymous function being passed to setTimeout()',
answer: 'The right answer is setTimeout',
explanation: "It's setTimeout because it's an async function and not sync",
flagReason: 'setTimeout takes a callback function and not a number',
module: {
name: 'Variables',
moduleId: 1
}
}

const mocks = [
{
request: {
query: DELETE_EXERCISE,
variables: { id: 1 }
},
result: {
data: {
deleteExercise: {
id: 1
}
}
}
},
{
request: {
query: REMOVE_EXERCISE_FLAG,
variables: {
id: 1
}
},
result: {
data: {
removeExerciseFlag: {
id: 1
}
}
}
}
]

const loadingMocks = [
{
request: {
query: DELETE_EXERCISE,
variables: { id: 1 }
},
result: {
data: {
deleteExercise: {
id: 1
}
}
},
// Keep the query at loading state for ~3170 years
delay: 100_000_000_000_000
}
]

describe('AdminLessonExerciseCard component', () => {
it('Should show explanation on click', async () => {
expect.assertions(1)

render(
<MockedProvider>
<Component user={user} exercise={exercise} />
</MockedProvider>
)

const btn = screen.getByText('Show explanation')
await userEvent.click(btn)

expect(screen.getByText('Hide explanation')).toBeInTheDocument()
})

it('Should remove exercise', async () => {
expect.assertions(1)

const onRemoveMock = jest.fn()

render(
<MockedProvider mocks={mocks}>
<Component user={user} exercise={exercise} onRemove={onRemoveMock} />
</MockedProvider>
)

const btn = screen.getByText('REMOVE EXERCISE')
await userEvent.click(btn)

expect(onRemoveMock).toBeCalled()
})

it('Should not call onRemove if not passed', async () => {
expect.assertions(1)

const onRemoveMock = jest.fn()

render(
<MockedProvider mocks={mocks}>
<Component user={user} exercise={exercise} />
</MockedProvider>
)

const btn = screen.getByText('REMOVE EXERCISE')
await userEvent.click(btn)

expect(onRemoveMock).not.toBeCalled()
})

it('Should unflag exercise', async () => {
expect.assertions(1)

const onUnflag = jest.fn()

render(
<MockedProvider mocks={mocks}>
<Component user={user} exercise={exercise} onUnflag={onUnflag} />
</MockedProvider>
)

const btn = screen.getByText('UNFLAG EXERCISE')
await userEvent.click(btn)

expect(onUnflag).toBeCalled()
})

it('Should not call unflag if not passed', async () => {
expect.assertions(1)

const onUnflag = jest.fn()

render(
<MockedProvider mocks={mocks}>
<Component user={user} exercise={exercise} />
</MockedProvider>
)

const btn = screen.getByText('UNFLAG EXERCISE')
await userEvent.click(btn)

expect(onUnflag).not.toBeCalled()
})

it('Should show loading spinner', async () => {
expect.assertions(1)

render(
<MockedProvider mocks={loadingMocks}>
<Component user={user} exercise={exercise} onRemove={() => {}} />
</MockedProvider>
)

const btn = screen.getByText('REMOVE EXERCISE')
await userEvent.click(btn)

expect(screen.queryByText('REMOVE EXERCISE')).not.toBeInTheDocument()
})

it('Should not show the explanation if not provided', () => {
expect.assertions(1)

render(
<MockedProvider mocks={mocks}>
<Component user={user} exercise={{ ...exercise, explanation: '' }} />
</MockedProvider>
)

expect(screen.queryByText('Show explanation')).not.toBeInTheDocument()
})
})
Loading