-
Notifications
You must be signed in to change notification settings - Fork 175
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
MWPW-148253 Quiz Entry Coverage #2305
Changes from all commits
1b2e32c
fdee326
e5f85f7
eb9d64a
b536cc2
07a349f
270c14b
9496008
2c3111b
779c9a0
aff5965
6b3f521
1646ab3
b2990db
f0dd5ec
a4bcd7c
3a09e65
6aee0ea
18677b3
5c543a4
49b0bc2
a0b27ca
0e652ce
e9ac496
c1b6e52
afd32b1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -78,7 +78,10 @@ export const handleSelections = (prevSelections, selectedQuestion, selections) = | |||||||||||
// de-dup any existing data if they use the ml field and cards. | ||||||||||||
if (prevSelections.length > 0) { | ||||||||||||
prevSelections.forEach((selection) => { | ||||||||||||
if (selection.selectedQuestion === selectedQuestion) { | ||||||||||||
const jsonSelectionSelectedQustion = JSON.stringify(selection.selectedQuestion); | ||||||||||||
colloyd marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||
const jsonSelectedQuesion = JSON.stringify(selectedQuestion[0].selectedQuestion); | ||||||||||||
const isSameQuestion = jsonSelectionSelectedQustion === jsonSelectedQuesion; | ||||||||||||
if (isSameQuestion) { | ||||||||||||
Comment on lines
+81
to
+84
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we can skip caching here and reduce the lines of code.
Suggested change
|
||||||||||||
selection.selectedCards = selections; | ||||||||||||
isNewQuestion = false; | ||||||||||||
} | ||||||||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -100,7 +100,7 @@ const resultsMock = { | |
options: 'photo', | ||
title: 'Photography', | ||
text: 'Edit or organize my photos', | ||
icon: '', | ||
icon: 'https://milo.adobe.com/drafts/quiz/quiz-ai/search.svg', | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does this ever get loaded? If so, it should be switched to a mock resource |
||
image: 'https://main--milo--adobecom.hlx.page/drafts/colloyd/quiz-entry/images/photography.png', | ||
}, | ||
{ | ||
|
@@ -664,7 +664,7 @@ const resultsMock = { | |
}, | ||
{ | ||
options: 'video', | ||
next: 'q-rather,q-video', | ||
next: 'RESET', | ||
type: 'card', | ||
endpoint: '', | ||
'api-key': '', | ||
|
Original file line number | Diff line number | Diff line change | ||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -3,7 +3,7 @@ import { readFile } from '@web/test-runner-commands'; | |||||||||||||||||
import { expect } from '@esm-bundle/chai'; | ||||||||||||||||||
import sinon from 'sinon'; | ||||||||||||||||||
import init from '../../../libs/blocks/quiz-entry/quiz-entry.js'; | ||||||||||||||||||
import { getSuggestions } from '../../../libs/blocks/quiz-entry/quizPopover.js'; // Correct the path as needed | ||||||||||||||||||
import { getSuggestions } from '../../../libs/blocks/quiz-entry/quizPopover.js'; | ||||||||||||||||||
|
||||||||||||||||||
let fetchStub; | ||||||||||||||||||
let quizEntryElement; | ||||||||||||||||||
|
@@ -156,4 +156,147 @@ describe('Quiz Entry Component', () => { | |||||||||||||||||
await new Promise((resolve) => setTimeout(resolve, 100)); | ||||||||||||||||||
expect(continueButton.classList.contains('disabled')).to.be.false; | ||||||||||||||||||
}); | ||||||||||||||||||
it('should navigate the carousel using keyboard commands', async () => { | ||||||||||||||||||
const options = document.querySelectorAll('.quiz-option'); | ||||||||||||||||||
const option = document.querySelector('.quiz-option'); | ||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Wouldn't this just be |
||||||||||||||||||
option.click(); | ||||||||||||||||||
await new Promise((resolve) => setTimeout(resolve, 100)); | ||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not a big fan of having timeouts in unit tests, as they tend to add up and then the test suite takes a long time to run. I think there was a way around this with |
||||||||||||||||||
const carousel = document.querySelector('.quiz-options-container'); | ||||||||||||||||||
const rightArrowEvent = new KeyboardEvent('keydown', { key: 'ArrowRight' }); | ||||||||||||||||||
const leftArrowEvent = new KeyboardEvent('keydown', { key: 'ArrowLeft' }); | ||||||||||||||||||
carousel.dispatchEvent(rightArrowEvent); | ||||||||||||||||||
await new Promise((resolve) => setTimeout(resolve, 100)); | ||||||||||||||||||
carousel.dispatchEvent(leftArrowEvent); | ||||||||||||||||||
Comment on lines
+165
to
+169
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit: Same here, we can skip caching
Suggested change
|
||||||||||||||||||
await new Promise((resolve) => setTimeout(resolve, 100)); | ||||||||||||||||||
const leftArrow = document.querySelector('.carousel-arrow.arrow-prev'); | ||||||||||||||||||
expect(leftArrow).to.not.exist; | ||||||||||||||||||
Comment on lines
+171
to
+172
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit: Same here, we can skip caching
Suggested change
|
||||||||||||||||||
|
||||||||||||||||||
const tabKeyEvent = new KeyboardEvent('keydown', { key: 'Tab' }); | ||||||||||||||||||
option.dispatchEvent(tabKeyEvent); | ||||||||||||||||||
Comment on lines
+174
to
+175
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit: Same here, we can skip caching. There are many optimising opportunities like this in the file, I won't add a comment for all of them. This is just a possible improvement to the code compactness, nothing critical.
Suggested change
|
||||||||||||||||||
await new Promise((resolve) => setTimeout(resolve, 100)); | ||||||||||||||||||
expect(option.classList.contains('selected')).to.be.true; | ||||||||||||||||||
|
||||||||||||||||||
const spaceKeyEvent = new KeyboardEvent('keydown', { key: ' ', keyCode: 32 }); | ||||||||||||||||||
carousel.dispatchEvent(spaceKeyEvent); | ||||||||||||||||||
await new Promise((resolve) => setTimeout(resolve, 100)); | ||||||||||||||||||
|
||||||||||||||||||
const enterKeyEvent = new KeyboardEvent('keydown', { | ||||||||||||||||||
key: 'Enter', | ||||||||||||||||||
code: 'Enter', | ||||||||||||||||||
keyCode: 13, | ||||||||||||||||||
}); | ||||||||||||||||||
carousel.dispatchEvent(enterKeyEvent); | ||||||||||||||||||
await new Promise((resolve) => setTimeout(resolve, 100)); | ||||||||||||||||||
expect(options[1].classList.contains('selected')).to.be.false; | ||||||||||||||||||
}); | ||||||||||||||||||
}); | ||||||||||||||||||
|
||||||||||||||||||
describe('RTL Quiz Entry', () => { | ||||||||||||||||||
beforeEach(async () => { | ||||||||||||||||||
window.lana = { log: sinon.stub() }; | ||||||||||||||||||
fetchStub = sinon.stub(window, 'fetch'); | ||||||||||||||||||
fetchStub.resolves({ | ||||||||||||||||||
ok: true, | ||||||||||||||||||
json: () => Promise.resolve({ suggested_completions: ['designer desk', 'design logos'] }), | ||||||||||||||||||
}); | ||||||||||||||||||
document.body.innerHTML = await readFile({ path: './mocks/index.html' }); | ||||||||||||||||||
document.documentElement.setAttribute('dir', 'rtl'); | ||||||||||||||||||
quizEntryElement = document.querySelector('.quiz-entry'); | ||||||||||||||||||
await init(quizEntryElement, quizConfig); | ||||||||||||||||||
await new Promise((resolve) => setTimeout(resolve, 100)); | ||||||||||||||||||
}); | ||||||||||||||||||
|
||||||||||||||||||
afterEach(() => { | ||||||||||||||||||
sinon.restore(); | ||||||||||||||||||
}); | ||||||||||||||||||
|
||||||||||||||||||
it('should navigate the carousel using keyboard commands', async () => { | ||||||||||||||||||
const options = document.querySelectorAll('.quiz-option'); | ||||||||||||||||||
const option = document.querySelector('.quiz-option'); | ||||||||||||||||||
option.click(); | ||||||||||||||||||
await new Promise((resolve) => setTimeout(resolve, 100)); | ||||||||||||||||||
const carousel = document.querySelector('.quiz-options-container'); | ||||||||||||||||||
const rightArrowEvent = new KeyboardEvent('keydown', { key: 'ArrowRight' }); | ||||||||||||||||||
const leftArrowEvent = new KeyboardEvent('keydown', { key: 'ArrowLeft' }); | ||||||||||||||||||
carousel.dispatchEvent(rightArrowEvent); | ||||||||||||||||||
await new Promise((resolve) => setTimeout(resolve, 100)); | ||||||||||||||||||
carousel.dispatchEvent(leftArrowEvent); | ||||||||||||||||||
await new Promise((resolve) => setTimeout(resolve, 100)); | ||||||||||||||||||
const leftArrow = document.querySelector('.carousel-arrow.arrow-prev'); | ||||||||||||||||||
expect(leftArrow).to.exist; | ||||||||||||||||||
|
||||||||||||||||||
const tabKeyEvent = new KeyboardEvent('keydown', { key: 'Tab' }); | ||||||||||||||||||
option.dispatchEvent(tabKeyEvent); | ||||||||||||||||||
await new Promise((resolve) => setTimeout(resolve, 100)); | ||||||||||||||||||
expect(option.classList.contains('selected')).to.be.false; | ||||||||||||||||||
|
||||||||||||||||||
const spaceKeyEvent = new KeyboardEvent('keydown', { key: ' ', keyCode: 32 }); | ||||||||||||||||||
carousel.dispatchEvent(spaceKeyEvent); | ||||||||||||||||||
await new Promise((resolve) => setTimeout(resolve, 100)); | ||||||||||||||||||
|
||||||||||||||||||
const enterKeyEvent = new KeyboardEvent('keydown', { | ||||||||||||||||||
key: 'Enter', | ||||||||||||||||||
code: 'Enter', | ||||||||||||||||||
keyCode: 13, | ||||||||||||||||||
}); | ||||||||||||||||||
carousel.dispatchEvent(enterKeyEvent); | ||||||||||||||||||
await new Promise((resolve) => setTimeout(resolve, 100)); | ||||||||||||||||||
expect(options[1].classList.contains('selected')).to.be.false; | ||||||||||||||||||
}); | ||||||||||||||||||
}); | ||||||||||||||||||
|
||||||||||||||||||
describe('ML Result Trigger', () => { | ||||||||||||||||||
beforeEach(async () => { | ||||||||||||||||||
window.lana = { log: sinon.stub() }; | ||||||||||||||||||
fetchStub = sinon.stub(window, 'fetch'); | ||||||||||||||||||
const mockApiResponse = { | ||||||||||||||||||
statusCode: 200, | ||||||||||||||||||
data: { | ||||||||||||||||||
data: [ | ||||||||||||||||||
{ | ||||||||||||||||||
ficode: 'illustrator_cc', | ||||||||||||||||||
prob: '0.33', | ||||||||||||||||||
}, | ||||||||||||||||||
{ | ||||||||||||||||||
ficode: 'indesign_cc', | ||||||||||||||||||
prob: '0.27', | ||||||||||||||||||
}, | ||||||||||||||||||
{ | ||||||||||||||||||
ficode: 'free_spark', | ||||||||||||||||||
prob: '0.22', | ||||||||||||||||||
}, | ||||||||||||||||||
], | ||||||||||||||||||
jobName: '', | ||||||||||||||||||
}, | ||||||||||||||||||
}; | ||||||||||||||||||
fetchStub.resolves({ | ||||||||||||||||||
ok: true, | ||||||||||||||||||
json: () => Promise.resolve(mockApiResponse.data), | ||||||||||||||||||
}); | ||||||||||||||||||
document.body.innerHTML = await readFile({ path: './mocks/index.html' }); | ||||||||||||||||||
quizEntryElement = document.querySelector('.quiz-entry'); | ||||||||||||||||||
await init(quizEntryElement, quizConfig); | ||||||||||||||||||
await new Promise((resolve) => setTimeout(resolve, 100)); | ||||||||||||||||||
}); | ||||||||||||||||||
|
||||||||||||||||||
afterEach(() => { | ||||||||||||||||||
sinon.restore(); | ||||||||||||||||||
}); | ||||||||||||||||||
|
||||||||||||||||||
it('Should trigger results fetching scenario', async () => { | ||||||||||||||||||
const mlInputField = document.querySelector('#quiz-input'); | ||||||||||||||||||
const testInput = 'design'; | ||||||||||||||||||
const inputEvent = new Event('input', { bubbles: true }); | ||||||||||||||||||
mlInputField.value = testInput; | ||||||||||||||||||
mlInputField.dispatchEvent(inputEvent); | ||||||||||||||||||
await new Promise((resolve) => setTimeout(resolve, 100)); | ||||||||||||||||||
|
||||||||||||||||||
const enterKeyEvent = new KeyboardEvent('keypress', { | ||||||||||||||||||
key: 'Enter', | ||||||||||||||||||
code: 'Enter', | ||||||||||||||||||
keyCode: 13, | ||||||||||||||||||
}); | ||||||||||||||||||
mlInputField.dispatchEvent(enterKeyEvent); | ||||||||||||||||||
expect(mlInputField.value).to.equal('design'); | ||||||||||||||||||
}); | ||||||||||||||||||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,149 @@ | ||
/* eslint-disable no-promise-executor-return */ | ||
import { readFile } from '@web/test-runner-commands'; | ||
import { expect } from '@esm-bundle/chai'; | ||
import sinon from 'sinon'; | ||
import { handleNext, getQuizJson, handleSelections, getQuizEntryData } from '../../../libs/blocks/quiz-entry/utils.js'; // Correct the path as needed | ||
|
||
let fetchStub; | ||
const { default: mockData } = await import('./mocks/mock-data.js'); | ||
const mockQuestionsData = mockData.questions; | ||
const mockStringsData = mockData.strings; | ||
const quizConfig = { | ||
quizPath: '/drafts/quiz/', | ||
maxQuestions: 1, | ||
analyticsQuiz: 'uarv4', | ||
analyticsType: 'cc:app-reco', | ||
questionData: undefined, | ||
stringsData: undefined, | ||
}; | ||
const selectedQuestion = { | ||
questions: 'q-category', | ||
'max-selections': '3', | ||
'min-selections': '1', | ||
}; | ||
const userInputSelections = { photo: true }; | ||
const userInputSelectionsNot = { '3d': true }; | ||
const userInputSelectionsReset = { video: true }; | ||
|
||
const userFlow = []; | ||
const nextFlow = { nextFlow: ['q-rather', 'q-photo'] }; | ||
const nextFlowNot = { nextFlow: ['q-3d'] }; | ||
const nextFlowReset = { nextFlow: [] }; | ||
const prevSelections = []; | ||
const selections = ['photo']; | ||
const nextSelectionsExpected = { | ||
nextSelections: [ | ||
{ | ||
selectedCards: [ | ||
'photo', | ||
], | ||
selectedQuestion: { | ||
'max-selections': '3', | ||
'min-selections': '1', | ||
questions: 'q-category', | ||
}, | ||
}, | ||
], | ||
}; | ||
|
||
describe('Quiz Entry Utils', () => { | ||
beforeEach(async () => { | ||
window.lana = { log: sinon.stub() }; | ||
fetchStub = sinon.stub(window, 'fetch'); | ||
fetchStub.resolves({ | ||
ok: true, | ||
json: () => Promise.resolve(mockData), | ||
}); | ||
}); | ||
|
||
afterEach(() => { | ||
sinon.restore(); | ||
}); | ||
|
||
it('should handle the next flow of questions', async () => { | ||
const nextQuestion = handleNext( | ||
mockQuestionsData, | ||
selectedQuestion, | ||
userInputSelections, | ||
userFlow, | ||
); | ||
expect(nextQuestion).to.deep.equal(nextFlow); | ||
}); | ||
|
||
it('should handle the next flow of questions with not()', async () => { | ||
const nextQuestion = handleNext( | ||
mockQuestionsData, | ||
selectedQuestion, | ||
userInputSelectionsNot, | ||
userFlow, | ||
); | ||
expect(nextQuestion).to.deep.equal(nextFlowNot); | ||
}); | ||
|
||
it('should handle the next flow of questions with reset()', async () => { | ||
const nextQuestion = handleNext( | ||
mockQuestionsData, | ||
selectedQuestion, | ||
userInputSelectionsReset, | ||
userFlow, | ||
); | ||
expect(nextQuestion).to.deep.equal(nextFlowReset); | ||
}); | ||
|
||
it('should fetch quiz data', async () => { | ||
const [questions, strings] = await getQuizJson('./mocks/'); | ||
expect(questions.questions).to.deep.equal(mockQuestionsData); | ||
expect(strings.strings).to.deep.equal(mockStringsData); | ||
}); | ||
}); | ||
|
||
describe('Quiz Entry Utils failed request', () => { | ||
beforeEach(async () => { | ||
window.lana = { log: sinon.stub() }; | ||
fetchStub = sinon.stub(window, 'fetch'); | ||
fetchStub.resolves({ ok: false }); | ||
}); | ||
|
||
afterEach(() => { | ||
sinon.restore(); | ||
}); | ||
|
||
it('should log an error when fetching quiz data fails', async () => { | ||
await getQuizJson('./mocks/'); | ||
expect(window.lana.log.called).to.be.true; | ||
}); | ||
it('should return nextSelections on handleSelections', async () => { | ||
const nextSelections = handleSelections(prevSelections, selectedQuestion, selections); | ||
expect(nextSelections).to.deep.equal(nextSelectionsExpected); | ||
}); | ||
|
||
it('should de-dup any existing data if they use the ml field and cards.', async () => { | ||
const prevSelectionsLength = [{ | ||
selectedQuestion: { | ||
'max-selections': '3', | ||
'min-selections': '1', | ||
questions: 'q-category', | ||
}, | ||
}]; | ||
|
||
const selectedQuestionPrev = [{ | ||
selectedQuestion: { | ||
'max-selections': '3', | ||
'min-selections': '1', | ||
questions: 'q-category', | ||
}, | ||
}]; | ||
|
||
const nextSelections = handleSelections(prevSelectionsLength, selectedQuestionPrev, selections); | ||
await new Promise((resolve) => setTimeout(resolve, 100)); | ||
expect(nextSelections).to.deep.equal(nextSelections); | ||
}); | ||
|
||
it('should return quizPath, maxQuestions, analyticsQuiz, analyticsType, questionData', async () => { | ||
document.body.innerHTML = await readFile({ path: './mocks/index.html' }); | ||
const el = document.querySelector('.quiz-entry'); | ||
|
||
const quizEntryData = await getQuizEntryData(el); | ||
expect(quizEntryData).to.deep.equal(quizConfig); | ||
}); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Have you considered assign? It may be useful to navigate back, if that's desired.