Skip to content

Commit

Permalink
initialized notes repo on Jest code.
Browse files Browse the repository at this point in the history
  • Loading branch information
j8ahmed committed Apr 22, 2021
1 parent 9b7c5b6 commit cd2ede5
Show file tree
Hide file tree
Showing 5 changed files with 261 additions and 63 deletions.
69 changes: 63 additions & 6 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,5 +41,12 @@
"last 1 firefox version",
"last 1 safari version"
]
},
"devDependencies": {
"@types/jest": "^26.0.22",
"@types/react": "^17.0.3",
"@types/react-dom": "^17.0.3",
"react-test-renderer": "^17.0.2",
"typescript": "^4.2.4"
}
}
48 changes: 25 additions & 23 deletions src/assets/animations.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,29 @@
import gsap from 'gsap'


export const app_load_anim = (tl = gsap.timeline({autoAlpha:0})) => {
tl
.fromTo(".app", {opacity: 0}, {opacity: 1})
.to(".app", {visibility: "visible"}, "<")
const animations = {
app_load_anim: (tl = gsap.timeline({autoAlpha:0})) => {
tl
.fromTo(".app", {opacity: 0}, {opacity: 1})
.to(".app", {visibility: "visible"}, "<")
return tl
},
question_load_anim: (tl = gsap.timeline({autoAlpha:0})) => {
tl
.fromTo(".question-set", {opacity: 0}, {opacity: 1})
.to(".question-set", {visibility: "visible"}, "<")


return tl
}

export const question_load_anim = (tl = gsap.timeline({autoAlpha:0})) => {
tl
.fromTo(".question-set", {opacity: 0}, {opacity: 1})
.to(".question-set", {visibility: "visible"}, "<")

return tl
return tl
},
question_remove_anim: (tl = gsap.timeline({autoAlpha:0})) => {
tl
.to(".question-set", {opacity: 0, duration: 0.1})

return tl
}
}


export const question_remove_anim = (tl = gsap.timeline({autoAlpha:0})) => {
tl
.to(".question-set", {opacity: 0, duration: 0.1})

return tl
}
export const {
app_load_anim,
question_load_anim,
question_remove_anim,
} = animations
export default animations
76 changes: 42 additions & 34 deletions src/components/QuestionCard.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { useState } from 'react'
import Controls from './Controls'
import QuestionSet from './QuestionSet'
import "../index.css"
import { useState } from 'react'
import { randomize } from '../assets/utilities'
import { fetchQuiz } from '../API/trivia_api'
import Controls from './Controls'
import QuestionSet from './QuestionSet'


export enum QuizStatus { LOADING, LOADED, COMPLETE, NOT_STARTED, QUESTION_ANSWERED, END_QUIZ }
Expand Down Expand Up @@ -84,39 +84,47 @@ const QuestionCard = () => {

const endQuiz = () => setStatus( QuizStatus.END_QUIZ )

if(status === QuizStatus.NOT_STARTED){
return <div className="question-card"><button className="start-btn" onClick={startQuiz} >Start Quiz</button></div>
}
switch(status){
case QuizStatus.NOT_STARTED:
return (
<div className="question-card">
<button className="start-btn" onClick={startQuiz}>Start Quiz</button>
</div>
)

if(status === QuizStatus.LOADING){
return <div className="question-card"><h3>Loading...</h3></div>
}

if(status === QuizStatus.END_QUIZ){
return (
<div className="question-card">
<h2>End of Quiz</h2>
<h3>{`Score: ${score} / ${questionDeck.length}`}</h3>
<button onClick={restartQuiz} className="start-btn">Start Another</button>
</div>
)
}
case QuizStatus.LOADING:
return (
<div className="question-card">
<h3>Loading...</h3>
</div>
)

case QuizStatus.END_QUIZ:
return (
<div className="question-card">
<h2>End of Quiz</h2>
<h3>{`Score: ${score} / ${questionDeck.length}`}</h3>
<button onClick={restartQuiz} className="start-btn">Start Another</button>
</div>
)

return (
<div className="question-card">
<h3 className="score">{`Score: ${score}`}</h3>
<QuestionSet
status={status}
questionState={status === QuizStatus.QUESTION_ANSWERED}
selectAnswer={selectAnswer}
{...question}/>
<Controls
isAnswered={status === QuizStatus.QUESTION_ANSWERED}
nextExists={question.id + 2 <= questionDeck.length}
next={nextQuestion}
end={endQuiz}/>
</div>
)
default:
return (
<div className="question-card">
<h3 className="score">{`Score: ${score}`}</h3>
<QuestionSet
status={status}
questionState={status === QuizStatus.QUESTION_ANSWERED}
selectAnswer={selectAnswer}
{...question}/>
<Controls
isAnswered={status === QuizStatus.QUESTION_ANSWERED}
nextExists={question.id + 2 <= questionDeck.length}
next={nextQuestion}
end={endQuiz}/>
</div>
)
}
}

export default QuestionCard
124 changes: 124 additions & 0 deletions src/tests/questioncard.implementation.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
import React from 'react'
import gsap from 'gsap'
import { render, unmountComponentAtNode } from 'react-dom'
import { act } from 'react-dom/test-utils'
import { convertTypeAcquisitionFromJson, isJSDocAugmentsTag } from 'typescript'

import App from '../App'
import QuestionCard from '../components/QuestionCard'
import Animations from '../assets/animations'

jest.mock('../assets/animations')

let container: HTMLElement | null

beforeEach(()=>{
// setup a DOM element as a render target
container = document.createElement('div') as HTMLElement
document.body.appendChild(container)
})

afterEach(()=>{
// cleanup on exiting of each test
unmountComponentAtNode(container as HTMLElement)
container?.remove()
container = null
})

test('Test that the App has the title Quiz App', ()=> {

act(()=>{
render(<App/>, container)
})
expect(container?.querySelector('h1')?.textContent).toBe('Quiz App')
})


test('Quiz Button fetches the Quiz data', async ()=>{
const fakeQuestions = [
{category: 'random', correct_answer: 'C', difficulty: 'normal', incorrect_answers: ['A', 'B', 'D'], question: 'What is your name?', type: 'MC',},
{category: 'random', correct_answer: 'C', difficulty: 'normal', incorrect_answers: ['A', 'B', 'D'], question: 'What is your number?', type: 'MC',},
{category: 'random', correct_answer: 'C', difficulty: 'normal', incorrect_answers: ['A', 'B', 'D'], question: 'Where are you from?', type: 'MC',},
{category: 'random', correct_answer: 'C', difficulty: 'normal', incorrect_answers: ['A', 'B', 'D'], question: 'How old are you?', type: 'MC',},
{category: 'random', correct_answer: 'C', difficulty: 'normal', incorrect_answers: ['A', 'B', 'D'], question: 'What do you study?', type: 'MC',},
]
// mock the global fetch function to return fake data
jest.spyOn(global, 'fetch').mockImplementation( () => {
return Promise.resolve({
json: () => Promise.resolve(fakeQuestions)
}) as Promise<Response>
})

jest.spyOn(Animations, 'app_load_anim')

// mock the animation functions to remove GSAP errors
// jest.spyOn(Animations, 'app_load_anim').mockImplementation( (tl = gsap.timeline()) => {
// // tl.to("*", {visibility: "visible"})
// return tl
// })

// const Animations = jest.createMockFromModule('../assets/animations')
// Animations.app_load_anim.mockImplementation(()=> "hello")

act(()=>{
// jest.mock('../assets/animations')
render(<QuestionCard/>, container)
})
const test = jest.fn()
test("Hello")
test.mockImplementationOnce((x, y) => x + y)
test.mockImplementationOnce((x, y) => console.log(x+y))
test(10, 15)
test(20, 33)
const newMock = new test((x:number) => x + 100)
// newMock.mockImplementationOnce((x:number, y:number) => console.log(x+y))
// console.log(newMock)
console.log(test.mock)
// expect(Animations.app_load_anim).toHaveBeenCalled()
expect(container?.querySelector('.start-btn')?.textContent).toBe('Start Quiz')
})



/**
* Console.log(test.mock)
* {
calls: [ [ 'Hello' ] ],
instances: [ undefined ],
invocationCallOrder: [ 2 ],
results: [ { type: 'return', value: undefined } ]
}
calls = An array of arrays which hold all the arguments
passed in as parameters for each call of the mock function.
instances = An array of all the objects instances that have been
instantiated from this mock function using 'new'. When
a mock function is called (i.e. mockFn()), the corresponding
'instances' value in the array will be undefined since
it was not a new instance of the mock function being built?
invocationCallOrder = An array of integers indicating in what order was
this particular mock function was called relative to
all the other mock functions that may exist in the
test sutie (test file). This replaced the previous
'mock timestamps' because multiple mock functions
could potentially share the same timestamp which
presented a problem when trying to test any
callorders between mocked functions.
results = An array containing the results of all calls that have been made
to this mock function. Each entry is an object with 2 properties.
Ex: {type: 'return', value: 25}
type =
'return' - call completed by returning normally.
'throw' - call completed by throwing a value as an Error.
'incomplete' - call has not yet completed.
This occurs if you test the result from within the
mock function itself, or from within a function that was
called by the mock.
value = The value that was thrown or returned.
value is undefined when type === 'incomplete'.
*/

0 comments on commit cd2ede5

Please sign in to comment.