How to work on coding challenges
Our goal is to develop a fun and clear interactive learning experience.
Designing interactive coding challenges is difficult. It would be much easier to write a lengthy explanation or to create a video tutorial. But for our core curriculum, we’re sticking with what works best for most people - a fully interactive, video game-like experience.
We want campers to achieve a flow state. We want them to build momentum and blast through our curriculum with as few snags as possible. We want them to go into the projects with confidence and gain wide exposure to programming concepts.
We are currently in version 9 of the curriculum which includes theory lessons, workshops, labs, review pages and quizzes.
The content for each challenge is stored in its markdown file. This markdown file is later converted to HTML using our tools to create interactive web pages.
You can find all of freeCodeCamp.org’s curricular content in the /curriculum/challenges directory.
Breakdown of the Core Curriculum
Section titled “Breakdown of the Core Curriculum”The core curriculum teaches full stack development and is broken down into the following certifications:
- Responsive Web Design Certification
- JavaScript Certification
- Front-End Development Libraries Certification
- Python Certification
- Relational Databases Certification
- Back-End Development and APIs Certification
Each certification is broken down into modules like Bash Fundamentals, Semantic HTML and Functional Programming.
Each module contains dozens of theory lessons, workshops, labs, review pages and quizzes.
Theory lessons are short text based lectures with interactive examples that teach the theory behind concepts including common data structures, CSS Grid and SQL.
Workshops are step based projects where campers get to practice what they learned in the theory lessons.
Labs are campers opportunity to test their problem solving skills and build out projects reviewing the concepts learned in the theory lessons and workshops.
Review pages have a complete list of concepts covered in the module.
Quizzes will test the campers understanding of the material before moving onto the next module.
Each of these components has its own tooling and style guides. If you are interested in contributing, refer to these specialized guides:
Set up the tooling for the Curriculum
Section titled “Set up the tooling for the Curriculum”Before you work on the curriculum, you would need to set up some tooling to help you test your changes. You can use any option from the below:
-
You can set up freeCodeCamp locally. This is highly recommended for regular/repeat contributions. This setup allows you to work and test your changes.
-
Use GitHub Codespaces, a free online dev environment. Clicking the button below will start a ready-to-code dev environment for freeCodeCamp in your browser. It only takes a few minutes.
Challenge Template
Section titled “Challenge Template”---id: Unique identifier (alphanumerical, MongoDB_id)title: Challenge TitlechallengeType: Integer, defined in `client/utils/challenge-types.js`demoType: onClick(labs) or onLoad(workshops)---
# --description--
Challenge description text, in markdown
```html<div>example code</div>```
# --before-all--
```js// This code will run before the learner's code and tests.let clock = __FakeTimers.install();globalThis.x = 1;// It is necessary for DOM challenges when something needs to be// mocked before the learner's code is evaluated. For example,// fake timers need to be set up ahead of time if the learner's code// will call setTimeout.```
# --before-each--
```js// Precisely when this is evaluated depends on the type of// challenge. HTML challenges run it after the learner's code,// but before each test. In all other challenges the order is// --before-each--, learner's code and then test code.const _testFixture = 'provides data for the tests';const clock = __FakeTimers.install();```
# --after-each--
```js// Undo any lasting changes caused by --before-each-- e.g.clock.uninstall();```
# --after-all--
```js// Undo any lasting changes caused by --before-all-- e.g.clock.uninstall();delete globalThis.x;```
# --hints--
Tests to run against user code, in pairs of markdown text and code block test code.
```jsCode for test one```
If you want dynamic output based on the user's code, --fcc-expected-- and --fcc-actual-- will be replaced with the expected and actual values of the test's assertion. Take care if you have multiple assertions since the first failing assertion will determine the values of --fcc-expected-- and --fcc-actual--.
```jsassert.equal( 'this will replace --fcc-actual--', 'this will replace --fcc-expected--');```
# --seed--
## --seed-contents--
Boilerplate code to render to the editor. This section should only contain code inside backticks, like the following:
```html<body> <p class="main-text">Hello world!</p></body>```
```cssbody { margin: 0; background-color: #3a3240;}
.main-text { color: #aea8d3;}```
```jsconsole.log('freeCodeCamp is awesome!');```
# --solutions--
Solutions are used for the CI tests to ensure that changes to the hints will still pass as intended
```js// first solution - the language(s) should match the seed.```
---
```js// second solution - so if the seed is written in HTML...```
---
```js// third solution etc. - Your solutions should be in HTML.```
# --assignments--
This will show a checkbox that campers have to check before completing a challenge
---
This will show another checkbox that campers have to check before completing a challenge
# --question--
These fields are currently used for the multiple-choice Python challenges.
## --text--
The question text goes here.
## --answers--
Answer 1
### --feedback--
This will be shown as feedback when campers guess this answer
---
Answer 2
---
More answers
## --video-solution--
The number for the correct answer goes here.Challenge descriptions/instructions
Section titled “Challenge descriptions/instructions”Sentences should be clear and concise with minimal jargon. If used, jargon should be immediately defined in plain English.
Keep paragraphs short (around 1-4 sentences). People are more likely to read several short paragraphs than a wall of text.
Use American English, e.g., use labeled instead of labelled.
Challenge text should use the second person (“you”) to help to give it a conversational tone. This way the text and instructions seem to speak directly to the camper working through the challenge. Try to avoid using the first person (“I”, “we”, “let’s”, and “us”).
Don’t use outbound links. These interrupt the flow. Campers should never have to google anything during these challenges. If there are resources you think campers would benefit from, add them to the challenge’s Guide-related article.
You can add diagrams if necessary.
Don’t use emojis or emoticons in challenges. freeCodeCamp has a global community, and the cultural meaning of an emoji or emoticon may be different around the world. Also, emojis can render differently on different systems.
Proper nouns should use correct capitalization when possible. Below is a list of words as they should appear in the challenges.
- JavaScript (capital letters in “J” and “S” and no abbreviations)
- Node.js
- When referring to front-end, back-end, or full-stack, use the hyphenated form.
The 2-minute rule
Section titled “The 2-minute rule”Each challenge should be solvable within 120 seconds by a native English speaker who has completed the challenges leading up to it. This includes the amount of time it takes to read the directions/instructions, understand the seeded code, write their code and get all the tests to pass.
If it takes longer than two minutes to complete the challenge, you have two options:
- Simplify the challenge, or
- Split the challenge into two challenges.
The 2-minute rule forces you, the challenge designer, to make your directions concise, your seed code clear, and your tests straightforward.
We track how long it takes for campers to solve challenges and use this information to identify challenges that need to be simplified or split.
Modularity
Section titled “Modularity”Each challenge should teach exactly one concept, and that concept should be apparent from the challenge’s name.
We can reinforce previously covered concepts through repetition and variations - for example, introducing h1 elements in one challenge, then h3 elements a few challenges later.
Our goal is to have thousands of 2-minute challenges. These can flow together and reiterate previously-covered concepts.
Formatting challenge text
Section titled “Formatting challenge text”In addition to the rules contained in the Writing Style Guide, here are specific formatting guidelines for challenge text and examples:
- Language keywords go in ``` backticks. For example, HTML tag names or CSS property names.
- References to code parts (i.e. function, method, or variable names) should be wrapped in ``` backticks. See example below:
Use `parseInt` to convert the variable `realNumber` into an integer.- References to file names and path directories (e.g.
package.json,src/components) should be wrapped in ``` backticks. - Multi-line code blocks must be preceded by an empty line. The next line must start with three backticks followed immediately by one of the supported languages. To complete the code block, you must start a new line that only has three backticks and another empty line. See example below:
- Whitespace matters in Markdown, so we recommend that you make it visible in your editor.
The following is an example of code:
```{language}
[YOUR CODE HERE]
```- Additional information in the form of a note should be surrounded by blank lines, and formatted:
**Note:** Rest of note text... - If multiple notes are needed, then list all of the notes in separate sentences using the format:
**Notes:** First note text. Second note text. - Use single quotes where applicable
Writing tests
Section titled “Writing tests”Challenges should have the minimum number of tests necessary to verify that a camper understands a concept.
Our goal is to communicate the single point that the challenge is trying to teach, and test that they have understood that point.
Challenge tests can make use of the Node.js and Chai.js assertion libraries. Also, if needed, user-generated code can be accessed in the code variable. In addition, the __helpers object exposes several functions that simplify the process of writing tests. The available functions are defined in the curriculum-helpers repo.
Guidelines for assertions
Section titled “Guidelines for assertions”If a method exists in Chai.js that expresses what is being tested for, its use is preferred.
Example one
assert(Array.isArray([]), 'empty arrays are arrays');Example two
assert.isArray([], 'empty arrays are arrays');In the first example, what the test means isn’t immediately clear. The main thing that explains the test is the assertion message.
Meanwhile in example two, the test spells out its purpose; to determine if something is an array.
Overall, we prefer the internal testing library implementation.
Formatting Seed Code
Section titled “Formatting Seed Code”Here are specific formatting guidelines for the challenge seed code:
- Use two spaces to indent for HTML, CSS, and JavaScript
- Use four spaces to indent for Python
- JavaScript statements end with a semicolon
- Use double quotes where applicable for HTML, CSS, and JavaScript
- Use single quotes where applicable for Python
Seed Code Comments
Section titled “Seed Code Comments”We have a comment dictionary that contains the only comments that can be used within the seed code. The exact case and spacing of the dictionary comment must be used. The comment dictionary should not be expanded without prior discussion with the dev-team.
Comments used should have a space between the comment characters and the comment themselves. In general, comments should be used sparingly. Always consider rewriting a challenge’s description or instructions if it could avoid using a seed code comment.
Example of a valid single-line JavaScript comment:
// Only change code below this lineExample of a valid CSS comment:
/* Only change code above this line */If a challenge only has a single place where code changes are needed, please use the comments in the following example to instruct the user where changes should be made.
// TODO: use a different type of loopfor (let i = 1; i <= count; i++) { rows.push(padRow(i, count));}Translation of Seed Code Comments
Section titled “Translation of Seed Code Comments”There are separate comment dictionaries for each language. The English version of the comment dictionary is the basis for the translations found in the corresponding non-English versions of the files. The non-English versions of the comment dictionaries are located in the i18n-curriculum git submodule at /curriculum/dictionaries/{language}/comments.json (for example, /curriculum/dictionaries/chinese/comments.json for Chinese). Each dictionary consists of an array of objects with a unique id property and a text property. Only the text should be modified to encompass the translation of the corresponding English comment.
Additionally, there is a comments-to-not-translate.json file that contains rules for comments that should remain in English and not be translated. This is usually used for comments added by the camper in workshops and tested by the tests of the steps.
Some comments may contain a word/phrase that should not be translated. For example, variable names or proper library names like “React” should not be translated. See the comment below as an example. The word myGlobal should not be translated.
Declare the myGlobal variable below this lineHints and Solutions
Section titled “Hints and Solutions”Each challenge has a Get a Hint button, so a user can access any hints/solutions which have been created for the challenge. Curriculum hints/solutions topics are located on our forum under the Guide category.
If you find a problem with an existing challenge’s hints/solutions topic, you can make suggestions in the contributors category on the forum. Moderators and users with trust level 3 will review the comments and decide whether or not to include the changes in the corresponding hint/solutions topic.
Testing Challenges
Section titled “Testing Challenges”Before you create a pull request for your changes, you need to validate that the changes you have made do not inadvertently cause problems with the challenge.
-
To test all challenges run the command below from the root directory
pnpm run test-curriculum-content- To test single challenge, you can use it challenge id with following command
FCC_CHALLENGE_ID=646cf6cbca98e258da65c979 pnpm run test-curriculum-content -
You can also test a block or a superblock of challenges with these commands
FCC_BLOCK='basic-html-and-html5' pnpm run test-curriculum-contentUse the block’s
dashedName(the folder’s name) for theFCC_BLOCKvalue.FCC_SUPERBLOCK='responsive-web-design' pnpm run test-curriculum-content
Proposing a Pull Request (PR)
Section titled “Proposing a Pull Request (PR)”After you’ve committed your changes, check here for how to open a Pull Request.
Useful Links
Section titled “Useful Links”- Challenge types - what the numeric challenge type values mean (enum).
Helper Scripts
Section titled “Helper Scripts”Creating a New Projects
Section titled “Creating a New Projects”To create a new lecture block, workshop, lab, review page or quiz, you can run pnpm run create-new-project in the root directory. This opens up a command line UI that guides you through the process.
Once that has finished, there should be a new challenge in the curriculum that you can use for the first step of the project. For example, if you created a project called test-project in the Responsive Web Design certification, it would be in curriculum/challenges/english/blocks/test-project.
There are a few other helper scripts that can be used to manage the challenges in a block. Note that these commands should all be run in the block directory. For example:
cd curriculum/challenges/english/blocks/basic-algorithm-scriptingAdd New Challenge
Section titled “Add New Challenge”To add a new challenge at the end of a block, call the script:
pnpm run create-next-challengeThis will prompt you for the challenge information and create the challenge file, updating the block’s JSON structure file with the new challenge information.
Delete a Challenge
Section titled “Delete a Challenge”To delete a challenge, call the script:
pnpm run delete-challengeThis will prompt you to select which challenge should be deleted, then delete the file and update the block’s JSON structure file to remove the challenge from the order.
Insert a Challenge
Section titled “Insert a Challenge”To insert a challenge before an existing challenge, call the script:
pnpm run insert-challengeThis will prompt you for the challenge information, then for the challenge to insert before. For example, if your choices are:
abcIf you choose b, your new order will be:
anew challengebcUpdate Challenge Order
Section titled “Update Challenge Order”If you need to manually re-order the challenges, call the script:
pnpm run update-challenge-orderThis will take you through an interactive process to select the order of the challenges.
Troubleshooting
Section titled “Troubleshooting”Infinite Loop Detected
Section titled “Infinite Loop Detected”If you see the following error in the console while previewing a challenge:
Potential infinite loop detected on line <number>...This means that the loop-protect plugin has found a long-running loop or recursive function. If your challenge needs to do that (e.g. it contains an event loop that is supposed to run indefinitely), then you can prevent the plugin from being used in the preview. To do so, add disableLoopProtectPreview: true to the block’s JSON structure file in curriculum/structure/blocks/.
If your tests are computationally intensive, then you may see this error when they run. If this happens then you can add disableLoopProtectTests: true to the block’s JSON structure file.
It’s not typically necessary to have both set to true, so only set them as needed.