diff --git a/spec/src/modules/quizzes.js b/spec/src/modules/quizzes.js index fb0ea02f..7e1c0c00 100644 --- a/spec/src/modules/quizzes.js +++ b/spec/src/modules/quizzes.js @@ -49,6 +49,104 @@ describe(`ConstructorIO - Quizzes${bundledDescriptionSuffix}`, () => { fetchSpy = null; }); + describe('getQuizAllQuestions', () => { + it('Should return a result provided a valid apiKey and quizId', () => { + const { quizzes } = new ConstructorIO({ + apiKey: quizApiKey, + fetch: fetchSpy, + }); + + return quizzes.getQuizAllQuestions(validQuizId).then((res) => { + const requestedUrlParams = helpers.extractUrlParamsFromFetch(fetchSpy); + + expect(res).to.have.property('quiz_version_id').to.be.an('string'); + expect(res).to.have.property('questions').to.be.an('array'); + expect(res.questions[0].id).to.equal(1); + expect(res.total_questions).to.equal(1); + expect(fetchSpy).to.have.been.called; + expect(requestedUrlParams).to.have.property('key'); + expect(requestedUrlParams).to.have.property('i'); + expect(requestedUrlParams).to.have.property('s'); + expect(requestedUrlParams).to.have.property('c').to.equal(clientVersion); + expect(requestedUrlParams).to.have.property('_dt'); + }); + }); + + it('Should return a result provided a valid apiKey, quizId and section', () => { + const section = 'Products'; + const { quizzes } = new ConstructorIO({ + apiKey: quizApiKey, + fetch: fetchSpy, + }); + + return quizzes.getQuizAllQuestions(validQuizId, { section }).then((res) => { + const requestedUrlParams = helpers.extractUrlParamsFromFetch(fetchSpy); + + expect(res).to.have.property('quiz_version_id').to.be.an('string'); + expect(res).to.have.property('questions').to.be.an('array'); + expect(fetchSpy).to.have.been.called; + expect(requestedUrlParams).to.have.property('section').to.equal(section); + }); + }); + + it('Should return a result provided a valid apiKey, quizId and quizVersionId', () => { + const { quizzes } = new ConstructorIO({ + apiKey: quizApiKey, + fetch: fetchSpy, + }); + + return quizzes.getQuizAllQuestions(validQuizId).then((initialResponse) => { + const quizVersionId = initialResponse.quiz_version_id; + + return quizzes.getQuizAllQuestions(validQuizId, { quizVersionId }).then((res) => { + const requestedUrlParams = helpers.extractUrlParamsFromFetch(fetchSpy); + + expect(res).to.have.property('questions').to.be.an('array'); + expect(res).to.have.property('quiz_version_id').to.be.an('string').to.equal(quizVersionId); + expect(res.total_questions).to.equal(1); + expect(fetchSpy).to.have.been.called; + expect(requestedUrlParams).to.have.property('quiz_version_id').to.equal(quizVersionId); + }); + }); + }); + + it('Should error when fetching quiz questions with an invalid quizId', () => { + const { quizzes } = new ConstructorIO({ + apiKey: quizApiKey, + fetch: fetchSpy, + }); + + return expect(quizzes.getQuizAllQuestions('invalidQuizId')).to.eventually.be.rejected; + }); + + it('Should error when fetching quiz questions with no quizId', () => { + const { quizzes } = new ConstructorIO({ + apiKey: quizApiKey, + fetch: fetchSpy, + }); + + return expect(quizzes.getQuizAllQuestions(null)).to.eventually.be.rejected; + }); + + it('Should error when fetching quiz questions with an invalid apiKey', () => { + const { quizzes } = new ConstructorIO({ + apiKey: 'invalidKey', + fetch: fetchSpy, + }); + + return expect(quizzes.getQuizAllQuestions(validQuizId)).to.eventually.be.rejected; + }); + + it('Should be rejected if an invalid quizVersionId is provided', () => { + const { quizzes } = new ConstructorIO({ + apiKey: quizApiKey, + fetch: fetchSpy, + }); + + return expect(quizzes.getQuizAllQuestions(validQuizId, { quizVersionId: 'foo' })).to.eventually.be.rejected; + }); + }); + describe('getQuizNextQuestion', () => { it('Should return a result provided a valid apiKey and quizId', () => { const { quizzes } = new ConstructorIO({ diff --git a/src/modules/quizzes.js b/src/modules/quizzes.js index 51b88786..24e2f1d7 100644 --- a/src/modules/quizzes.js +++ b/src/modules/quizzes.js @@ -263,6 +263,52 @@ class Quizzes { throw new Error('getQuizResultsConfig response data is malformed'); }); } + + /** + * Retrieves all questions for a particular quiz + * + * @function getQuizAllQuestions + * @description Retrieve all questions for a particular quiz from Constructor.io API + * @param {string} quizId - The identifier of the quiz + * @param {object} parameters - Additional parameters + * @param {string} [parameters.section] - Product catalog section + * @param {string} [parameters.quizVersionId] - Version identifier for the quiz. Version ID will be returned with the first request and it should be passed with subsequent requests. More information can be found: https://docs.constructor.com/reference/configuration-quizzes + * @param {string} [parameters.quizSessionId] - Session identifier for the quiz. Session ID will be returned with the first request or with getQuizResultsConfig and it should be passed with subsequent requests. More information can be found: https://docs.constructor.com/reference/configuration-quizzes + * @param {object} [networkParameters] - Parameters relevant to the network request + * @param {number} [networkParameters.timeout] - Request timeout (in milliseconds) + * @returns {Promise} + * @example + * constructorio.quizzes.getQuizAllQuestions('quizId', { + * quizVersionId: '123', + * }); + */ + getQuizAllQuestions(quizId, parameters, networkParameters = {}) { + let requestUrl; + const { fetch } = this.options; + const controller = new AbortController(); + const { signal } = controller; + + try { + requestUrl = createQuizUrl(quizId, parameters, this.options, 'all_questions'); + } catch (e) { + return Promise.reject(e); + } + + // Handle network timeout if specified + helpers.applyNetworkTimeout(this.options, networkParameters, controller); + + return fetch(requestUrl, { signal }) + .then(helpers.convertResponseToJson) + .then((json) => { + if (json.quiz_version_id) { + this.eventDispatcher.queue('quizzes.getQuizAllQuestions.completed', json); + + return json; + } + + throw new Error('getQuizAllQuestions response data is malformed'); + }); + } } module.exports = Quizzes; diff --git a/src/types/quizzes.d.ts b/src/types/quizzes.d.ts index fccb725c..98e546df 100644 --- a/src/types/quizzes.d.ts +++ b/src/types/quizzes.d.ts @@ -68,6 +68,14 @@ export interface NextQuestionResponse extends Record { total_questions: number; } +export interface AllQuestionsResponse extends Record { + questions: Question[]; + quiz_version_id?: string; + quiz_id?: string; + quiz_session_id?: string; + total_questions: number; +} + export interface QuizResultsResponse extends Record { request?: { filters?: Record;