Skip to content

Commit 5722856

Browse files
terichadbourneZé Bateirazebateira
authored
Create multiple choice quizzes using ProtoWizard CLI (#560)
* WIP * WIP: too much at once * WIP cleanup * rename file * add clean quiz.js * add selectLesson & promptFilesReady * delete old draft messy_quiz.js * add createQuiz and afterQuizCreate * Add updateQuiz to API * improve selectLesson UX * add pristine status and overwrite warnings * remove old comments * Update scripts/commands/wizard/quiz.js Co-authored-by: Zé Bateira <[email protected]> * incorporate review feedback * fix typos * Update guide to reflect mult choice creation via ProtoWizard * change npm run serve to npm start * WIP add jest tests for quiz * exclude specific logs from snapshot * add TODOs * add addl quiz tests * fix overwrite quiz logic * add assertUpdatedQuiz * WIP add assertQuiz x2 versions * WIP fix Jest 4.3, bugs in 4.1 & 4.2 * fix: spacing on assertQuizUnknownOrder * fix async expression in createQuiz * update snapshots for now-passing jest 4.2 * clean up console logs and comments * simplify logging of quiz choices * make ProtoWizard singular & more human * WIP: add testing docs * update wording in logCreateLater * Update jest/helpers/asserts.js Co-authored-by: Zé Bateira <[email protected]> * Update scripts/commands/wizard/quiz.js Co-authored-by: Zé Bateira <[email protected]> * Update src/api/modules/lessons.js Co-authored-by: Zé Bateira <[email protected]> * Update scripts/__tests__/protowizard/quizzes.spec.js Co-authored-by: Zé Bateira <[email protected]> * apply review suggestions Co-authored-by: Zé Bateira <[email protected]> Co-authored-by: Ze Bateira <[email protected]>
1 parent 1c49963 commit 5722856

File tree

23 files changed

+875
-111
lines changed

23 files changed

+875
-111
lines changed

DEVELOPING_TUTORIALS.md

Lines changed: 30 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ There are four lesson formats available, which you may mix and match within your
7979

8080
To build any of these lesson types, you'll need to use Markdown, a fairly simple way to style text on the web. [Learn more about Markdown formatting here.](https://guides.github.com/features/mastering-markdown/)
8181

82-
To create text-based or multiple-choice lessons, no prior coding knowledge is required. Our text-only lessons are written exclusively in Markdown, and you'll only need to do some simple text replacements in our JavaScript boilerplate to set up questions and answers for multiple-choice quizzes.
82+
To create text-based or multiple-choice lessons, no prior coding knowledge is required, as the content of these lessons is written in Markdown. To create the question and answer choices for a multiple-choice quiz, you can either use the ProtoWizard or make some text edits to the provided JavaScript template.
8383

8484
However, if you want to create code challenges (with or without file upload), you'll need to use JavaScript extensively to set up your default and solution code and validation. JavaScript is a scripting language for building interactive web pages, and you should have a solid understanding of JavaScript before building a code challenge for ProtoSchool.
8585

@@ -124,7 +124,7 @@ $ npm install
124124
5. Run the dev server locally:
125125

126126
```sh
127-
$ npm run serve
127+
$ npm start
128128
```
129129

130130
6. Open a web browser to the following address to preview your work: http://localhost:3000
@@ -140,7 +140,7 @@ We've included instructions in this guide for doing all of this manually (in cas
140140

141141
#### Using the ProtoWizard CLI (recommended)
142142

143-
The ProtoWizard is a CLI (Command-Line Interface) that makes it easy to create the starter files and metadata needed for a new tutorial. You can build your full tutorial at once, creating your tutorial metadata (URL, description, etc.), lesson files, and resources in one go. Alternatively, you can create your tutorial framework and then come back to add lessons and resources as you're ready.
143+
The ProtoWizard is a CLI (Command-Line Interface) that makes it easy to create the starter files and metadata needed for a new tutorial. You can build your full tutorial at once, creating your tutorial metadata (URL, description, etc.), lesson files, and resources in one go. Alternatively, you can create your tutorial framework and then come back to add lessons and resources as you're ready. You can even summon the ProtoWizard to build the quizzes for your multiple-choice lessons.
144144

145145
It's easy to use the ProtoWizard even if you're not familiar with the command line. It will ask you a few questions and let you type your answers or select options using arrow keys. Based on your answers, the ProtoWizard will build the directory, files, and metadata you'll need to create your tutorial.
146146

@@ -157,12 +157,12 @@ First, install the wizard:
157157
$ npm run install-protowizard
158158
```
159159

160-
Once the wizard is installed, you'll be able to launch it repeatedly with the shortcut command:
160+
Once the wizard is installed, you'll be able to summon it repeatedly with the shortcut command:
161161
```sh
162162
$ protowizard
163163
```
164164

165-
If you choose not to install it, you'll need to use this longer command to run the ProtoWizard:
165+
If you choose not to install it, you'll need to use this longer command to summon the ProtoWizard:
166166
```sh
167167
$ npm run scripts:wizard
168168
```
@@ -176,7 +176,7 @@ When you run either of the commands above to start the CLI, our friendly little
176176

177177
![screenshot](public/protowizard.png)
178178

179-
If you're creating a new tutorial from scratch, you'll need to create a tutorial before adding lessons or resources to it. You can either add your lessons and resources immediately after creating the tutorial or exit the ProtoWizard and run it again later to create those items.
179+
If you're creating a new tutorial from scratch, you'll need to create a tutorial before adding lessons or resources to it. You can either add your lessons and resources immediately after creating the tutorial or exit the ProtoWizard and run it again later to create those items. To create a multiple-choice quiz, you'll need to have first created your tutorial and lesson files.
180180

181181
By keeping your server running, you can preview your new tutorial in a web browser while using the ProtoWizard to add content.
182182

@@ -190,16 +190,22 @@ While the ProtoWizard only supports the initial creation of this data, you can e
190190

191191
Tell the ProtoWizard the name of your lesson and its type (text-only, multiple-choice, coding challenge with or without file upload) and it will create all the starter files you need inside your tutorial's directory. ([Learn more about the files required for each lesson type.](#create-lesson-files)) The ProtoWizard will provide you with the names of the files it's created so you'll know where to go to make your edits.
192192

193-
If you have a solid outline, you can create these files all at once before editing them to create your content. Alternatively, you can set up just the files for your first lesson, build out that content to get familiar with the process, and return to the ProtoWizard later to create your next set of files. It's up to you.
193+
If you have a solid outline, you can create these files all at once before editing them to create your content. Alternatively, you can set up just the files for your first lesson, build out that content to get familiar with the process, and summon the ProtoWizard again later to create your next set of files. It's up to you.
194194

195195
This guide includes detailed instructions on how to work within those files to [create your lesson content](#create-your-lesson-content) when you're ready.
196196

197197
**Resources**
198198

199-
Each ProtoSchool tutorial ends with a resources page where you can share suggestions of other learning materials relevant to your learners. The ProtoWizard will ask you a few quick questions about each resource in order to add the necessary details your tutorial's metadata. You can add all of your entries in the ProtoWizard at once or come back to it as you think of more resources.
199+
Each ProtoSchool tutorial ends with a resources page where you can share suggestions of other learning materials relevant to your learners. The ProtoWizard will ask you a few quick questions about each resource in order to add the necessary details your tutorial's metadata. You can add all of your entries at once or come summon the ProtoWizard repeatedly as you think of more resources.
200200

201201
If you'd like to make edits to the resources you've created through the ProtoWizard, you can edit the details later in `src/static/tutorials.json`. [Learn how to create or edit resources manually.](#manage-your-tutorials-metadata)
202202

203+
**Multiple-choice quizzes**
204+
205+
Each multiple-choice lesson ends with a quiz to reinforce the lesson content. With the help of the ProtoWizard, you'll draft the question the learner needs to answer, then provide answer choices and feedback positive or negative feedback to display when each option is selected.
206+
207+
The ProtoWizard will provide you with a link to the updated quiz file so you can make further edits as needed, or you can summon the ProtoWizard again to start from scratch and overwrite the quiz content. [Learn how to create or edit quizzes manually.](#create-multiple-choice-quizzes-skip-for-coding-challenges-and-text-only-lessons)
208+
203209
#### Manually
204210

205211
This section describes how to build the directory, lesson files, and metadata for your tutorial manually if you've chosen not to use the recommended ProtoWizard. If you've used the [ProtoWizard](#using-the-protowizard-cli-recommended) to create your tutorial, lesson files, and resources, please skip to [Create Your Lesson Content](#create-your-lesson-content).
@@ -432,7 +438,15 @@ Then in your lesson Markdown file, you can either add the image with regular Mar
432438

433439
#### Create multiple-choice quizzes (skip for coding challenges and text-only lessons)
434440

435-
When creating a multiple-choice lesson, you'll use your JavaScript (eg `01.js`) file to define the question and its answer choices.
441+
We recommend that you [use the ProtoWizard to create your multiple-choice quizzes](#using-the-protowizard-cli-recommended).
442+
443+
However, you may instead choose to edit your JavaScript (eg `01.js`) file directly to define the question and its answer choices, as described below.
444+
445+
When editing manually, please be sure to remove the following line of code:
446+
```
447+
// #PRISTINE# This file was auto-generated. Please remove this line when updating the file manually.
448+
```
449+
This will allow the ProtoWizard to identify the file as having been edited, so that it can warn you if you later ask to overwrite existing content.
436450

437451
The `question` value must be a string:
438452

@@ -448,26 +462,26 @@ const question = "What's the meaning of life, the universe, and everything?"
448462
```js
449463
const choices = [
450464
{
451-
answer: 'An incorrect answer',
465+
answer: "An incorrect answer",
452466
correct: false,
453-
feedback: 'Oops. Here\'s some clue about why that answer is wrong.'
467+
feedback: "Oops. Here's some clue about why that answer is wrong."
454468
},
455469
{
456-
answer: 'A correct answer.',
470+
answer: "A correct answer.",
457471
correct: true,
458-
feedback: 'Great job!'
472+
feedback: "Great job!"
459473
},
460474
{
461-
answer: 'A different incorrect answer',
475+
answer: "A different incorrect answer",
462476
correct: false,
463-
feedback: 'Sorry, here\'s some clue about why this choice is wrong.'
477+
feedback: "Sorry, here's some clue about why this choice is wrong."
464478
}
465479
]
466480
```
467481

468482
Please provide 3-5 answer choices per question. **You may only provide _one_ correct choice.**
469483

470-
The answer choices will be presented in the order in which you list them. Be sure to vary the position of the correct answer from lesson to lesson.
484+
If you create the quiz manually, the answer choices will be presented in the order in which you list them. Be sure to vary the position of the correct answer from lesson to lesson. (When using the ProtoWizard, your choices will be shuffled automatically.)
471485

472486
The `feedback` provided for each choice will be shown highlighted in red if incorrect or in green if correct, and the user will be able to advance to next lesson once they've made the right selection.
473487

README.md

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,20 +35,24 @@ $ git clone https://github.com/ProtoSchool/protoschool.github.io.git
3535
$ cd protoschool.github.io
3636
$ git checkout existing-branch-name-from-PR
3737
$ npm install
38-
$ npm run serve
38+
$ npm start
3939
```
4040

4141
View the site on localhost at: http://localhost:3000
4242

4343
## Testing without affecting site analytics in Countly
4444

45-
Only actions taken at the https://proto.school domain affect our main ProtoSchool analytics in Countly.
45+
Only actions taken at the https://proto.school domain affect our main ProtoSchool analytics in Countly.
4646

47-
You can safely experiment with any of the following to send stats to our TEST ProtoSchool dashboard in Countly instead:
47+
You can safely experiment with any of the following to send stats to our TEST ProtoSchool dashboard in Countly instead:
4848
- served locally: http://localhost:3000
4949
- live site accessed directly through Fleek: https://protoschool.on.fleek.co/
5050
- preview for a specific PR via link found in PR testing section (e.g. https://bafybeihebd2p64xghtqjuewonkfm4l5n2lkvrllviz7nb33qtyir5q5fau.on.fleek.co/)
5151

52+
## Testing suites
53+
54+
We use Cypress and Jest for testing. Please check the documentation [here](scripts/README.md) for further details.
55+
5256
## Managing remote data
5357

5458
Some data, such as the events list, is pulled at build-time from remote sources using Node.js scripts. Please check the documentation [here](scripts/README.md) for further details.

jest/helpers/asserts.js

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,21 @@
1+
// ** SNAPSHOT FILTERING ***
2+
// prevent snapshots for logs that change on each instance, such as shuffled quiz options
3+
4+
const excludedPhrases = [
5+
"Cool! Here's what we get when we mix up the order of the answer choices:"
6+
]
7+
8+
// returns true if log includes a string from the excludedPhrases array
9+
function isExcluded (log) {
10+
return excludedPhrases.some(phrase => log.includes(phrase))
11+
}
12+
13+
// add log to snapshot UNLESS it contains an excluded phrase
114
function assertLogSnapshot (log) {
2-
expect(log).toMatchSnapshot()
15+
if (!isExcluded(log)) {
16+
expect(log).toMatchSnapshot() // expect if log isn't excluded from assertion
17+
}
18+
// do nothing if log is excluded from assertion
319
}
420

521
module.exports = { assertLogSnapshot }

jest/helpers/fixtures.js

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ function createTutorial (config = { override: {}, lessons: 0, resources: 0 }) {
1818

1919
// Generators: generate data to be used
2020

21-
function generateTutorial (config = { override: {}, lessons: 0, resources: 0 }) {
21+
function generateTutorial (config = { override: {}, lessons: 0, resources: 0, lessonOverride: {} }) {
2222
const suffix = api.tutorials.getNextTutorialId()
2323

2424
const tutorial = {
@@ -30,7 +30,12 @@ function generateTutorial (config = { override: {}, lessons: 0, resources: 0 })
3030
}
3131

3232
const lessons = new Array(config.lessons).fill().map((_, i) => (
33-
generateLesson({ override: { title: `Lesson ${i + 1}` } }).lesson
33+
generateLesson({
34+
override: {
35+
title: `Lesson ${i + 1}`,
36+
...config.lessonOverride
37+
}
38+
}).lesson
3439
))
3540

3641
const resources = new Array(config.resources).fill().map((_, i) => (

public/protowizard.png

11.8 KB
Loading

scripts/README.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,24 @@ To update one or more ToCs on demand (without automatically saving), you can run
2525
- `npm run build:docs:develop` - update TOC in DEVELOPING_TUTORIALS.md
2626
- `npm run build:docs` - update ToC in both files
2727

28+
## Testing
29+
We use a number of test suites to ensure the best possible user experience. These tests are run automatically for each pull request and build.
30+
31+
When submitting a PR for a new feature, please include updated tests as well. You can use the following tools and commands to build your tests.
32+
33+
### Cypress
34+
Cypress provides end-to-end testing that mimics the user's experience with our interface.
35+
36+
TODO: add link to docs, most common commands and flags, incl how to keep window open, whether or not screenshots need to be committed, etc.
37+
38+
39+
### Jest
40+
Jest is used for snapshot testing of our CLI, the ProtoWizard.
41+
42+
TODO: add link to docs, most common commands and flags, incl when and how to update (and when not to update) snapshots
43+
44+
45+
2846
## Event and Newsletter Data Import
2947

3048
This project depends on some remote sources for data:

scripts/__tests__/helpers/asserts.js

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
const fs = require('fs')
2+
13
// Used with generateTutorial
24
function assertNewTutorial ({ context, result, expected }) {
35
expect(result).toBeInstanceOf(Object)
@@ -54,8 +56,28 @@ function assertNewResource ({ result, expected }) {
5456
expect(result.resources[0]).toMatchObject(expected.resource)
5557
}
5658

59+
function assertQuizUnknownOrder ({ result, hardcodedData }) {
60+
const fileContents = fs.readFileSync(result.files.js, 'utf8')
61+
expect(fileContents).toContain(`question = "${hardcodedData.question}"`)
62+
hardcodedData.choices.forEach(choice => {
63+
expect(fileContents).toContain(`{
64+
"answer": "${choice.answer}",
65+
"correct": ${choice.correct},
66+
"feedback": "${choice.feedback}"
67+
}`)
68+
})
69+
}
70+
71+
function assertQuizKnownOrder ({ result }) {
72+
const fileContents = fs.readFileSync(result.lessons[0].files.js, 'utf8')
73+
74+
expect(fileContents).toMatchSnapshot()
75+
}
76+
5777
module.exports = {
5878
assertNewTutorial,
5979
assertNewLesson,
60-
assertNewResource
80+
assertNewResource,
81+
assertQuizKnownOrder,
82+
assertQuizUnknownOrder
6183
}

0 commit comments

Comments
 (0)