fix(curriculum): grammar and test fixes in fcc-authors-page workshop (#69589)

Co-authored-by: sembauke <sembauke@users.noreply.github.com>
This commit is contained in:
Sem Bauke
2026-08-27 18:10:29 +02:00
committed by GitHub
parent fa1d624bfe
commit 9d84404f53
15 changed files with 69 additions and 51 deletions
@@ -14,7 +14,7 @@ All of the HTML and CSS for this workshop has been provided for you. You can tak
When you are ready, start by accessing the `#author-container` and `#load-more-btn` elements. Remember you can use the `getElementById` or `querySelector` methods for this.
Then assign these elements to variables called `authorContainer` and `loadMoreBtn`, respectively.
Then assign these elements to variables called `authorContainer` and `loadMoreBtn`, respectively.
# --hints--
@@ -64,7 +64,7 @@ assert.match(code, /fetch\(\s*('|"|`)https:\/\/cdn\.freecodecamp\.org\/curriculu
Your second `.then()` should not have semicolon after it.
```js
assert.notMatch(code, /fetch\(\s*('|"|`)https:\/\/cdn\.freecodecamp\.org\/curriculum\/news\-author\-page\/authors\.json\1\s*\)\s*\.then\(\s(\(\s*res\s*\)|res)\s*=>\s*res\.json\(\s*\)\s*\)\s*\.then\(\s*(\(\s*data\s*\)|data)\s*=>\s*\{\s*\n?\s*?console\.log\(\s*data\s*\)\s*;?\s*\}\s*\)\s*;/)
assert.notMatch(code, /fetch\(\s*('|"|`)https:\/\/cdn\.freecodecamp\.org\/curriculum\/news\-author\-page\/authors\.json\1\s*\)\s*\.then\(\s*(\(\s*res\s*\)|res)\s*=>\s*res\.json\(\s*\)\s*\)\s*\.then\(\s*(\(\s*data\s*\)|data)\s*=>\s*\{\s*\n?\s*?console\.log\(\s*data\s*\)\s*;?\s*\}\s*\)\s*;/)
```
# --seed--
@@ -75,7 +75,7 @@ You should add an `err` parameter to your `.catch()` method.
assert.match(code, /fetch\(\s*('|"|`)https:\/\/cdn\.freecodecamp\.org\/curriculum\/news\-author\-page\/authors\.json\1\s*\)\s*\.then\(\s*(\(\s*res\s*\)|res)\s*=>\s*res\.json\(\s*\)\s*\)\s*\.then\(\s*(\(\s*data\s*\)|data)\s*=>\s*\{\s*\n?\s*?console\.log\(\s*data\s*\)\s*;?\n?\s*\}\s*\)\n?\s*\.catch\(\s*(\(\s*err\s*\)|err)/)
```
Your `.catch()` method should have an arrow function syntax.
Your `.catch()` method should use arrow function syntax.
```js
assert.match(code, /fetch\(\s*('|"|`)https:\/\/cdn\.freecodecamp\.org\/curriculum\/news\-author\-page\/authors\.json\1\s*\)\s*\.then\(\s*(\(\s*res\s*\)|res)\s*=>\s*res\.json\(\s*\)\s*\)\s*\.then\(\s*(\(\s*data\s*\)|data)\s*=>\s*\{\s*\n?\s*?console\.log\(\s*data\s*\)\s*;?\n?\s*\}\s*\)\n?\s*\.catch\(\s*(\(\s*err\s*\)|err)\s*=>\s*\{?/)
@@ -197,7 +197,7 @@ fetch('https://cdn.freecodecamp.org/curriculum/news-author-page/authors.json')
.then((res) => res.json())
.then((data) => {
console.log(data);
});
})
--fcc-editable-region--
--fcc-editable-region--
@@ -28,7 +28,9 @@ window.fetch = () => Promise.resolve({json: () => Promise.resolve([{ author: 'Wh
You should use `let` to declare a variable named `startingIndex`.
```js
assert.match(code, /let\s+startingIndex/);
const explorer = await __helpers.Explorer(code);
const { startingIndex } = explorer.variables;
assert.isTrue(startingIndex?.toString().startsWith('let'));
```
Your `startingIndex` variable should be a number.
@@ -46,7 +48,9 @@ assert.strictEqual(startingIndex, 0);
You should use `let` to declare a variable named `endingIndex`.
```js
assert.match(code, /let\s+endingIndex/);
const explorer = await __helpers.Explorer(code);
const { endingIndex } = explorer.variables;
assert.isTrue(endingIndex?.toString().startsWith('let'));
```
Your `endingIndex` variable should be a number.
@@ -32,7 +32,7 @@ window.fetch = () => Promise.resolve({json: () => Promise.resolve([{ author: 'Wh
# --hints--
`displayAuthors` should be a function.
Your `displayAuthors` variable should be a function.
```js
assert.isFunction(displayAuthors)
@@ -41,13 +41,15 @@ assert.isFunction(displayAuthors)
Your `displayAuthors` function should take an `authors` parameter.
```js
assert.match(
code,
/(?:function\s+displayAuthors\s*\(\s*authors\s*\)|(?:const|let|var)\s+displayAuthors\s*=\s*(?:async\s*)?(?:\(\s*authors\s*\)|authors)\s*=>)/
const explorer = await __helpers.Explorer(code);
const { displayAuthors } = explorer.allFunctions;
assert.deepEqual(
displayAuthors?.parameters.map((p) => p.toString()),
['authors']
);
```
When the `displayAuthors` function is called with an author's array, it should add a card for each author to the `#authorContainer` element.
Your `displayAuthors` function should add a card for each author to the `authorContainer` element.
```js
const exampleAuthors = [
@@ -9,7 +9,7 @@ dashedName: step-10
Now `authorDataArr` is the same as the `data` you logged to the console a while ago. Log `authorDataArr` to the console to confirm this.
Inside your `console.log()` statement, add the text `"Author Data Array:"` as the first argument and `authorDataArr` as the second argument. Use comma to separate the text from `authorDataArr`.
Inside your `console.log()` statement, add the text `"Author Data Array:"` as the first argument and `authorDataArr` as the second argument. Use a comma to separate the text from `authorDataArr`.
# --before-all--
@@ -31,13 +31,13 @@ You should have a console log with the text `"Author Data Array:"`.
assert.match(code, /console\.log\(\s*("|'|`)Author\s+Data\s+Array:\s*\1/)
```
You should use comma to separate your `"Author Data Array:"` text and `authorDataArr`.
You should use a comma to separate your `"Author Data Array:"` text and `authorDataArr`.
```js
assert.match(code, /console\.log\(\s*("|'|`)Author\s+Data\s+Array:\s*\1\s*,/)
```
`authorDataArr` should be the second argument of your console log statement.
Your `authorDataArr` should be the second argument of the `console.log()` statement.
```js
assert.match(code, /console\.log\(\s*("|'|`)Author\s+Data\s+Array:\s*\1\s*,\s*authorDataArr\s*\)\s*;?/)
@@ -43,13 +43,13 @@ You should call your `displayAuthors` function and pass in an argument of `autho
assert.match(code, /displayAuthors\(\s*authorDataArr\.slice\(/)
```
The first parameter of your `slice()` method should be `startingIndex`.
Your first `slice()` argument should be `startingIndex`.
```js
assert.match(code, /displayAuthors\(\s*authorDataArr\.slice\(\s*startingIndex/)
```
The second parameter of your `slice()` method should be `endingIndex`.
Your second `slice()` argument should be `endingIndex`.
```js
assert.match(code, /displayAuthors\(\s*authorDataArr\.slice\(\s*startingIndex\s*,\s*endingIndex\s*\)\s*\)\s*;?/)
@@ -9,7 +9,7 @@ dashedName: step-15
Now you have everything you want to include in the UI. The next step is to make the `Load More Authors` button fetch more authors whenever it's clicked. You can do this by adding a `click` event to the button and carefully incrementing the `startingIndex` and `endingIndex` variables.
Create a `fetchMoreAuthors` function with the arrow function syntax. Don't put anything in it yet. Make sure you use curly braces because you'll have more than one expression inside the function.
Use `const` to create a `fetchMoreAuthors` function with the arrow function syntax. Don't put anything in it yet. Make sure you use curly braces because you'll have more than one expression inside the function.
# --before-all--
@@ -22,31 +22,38 @@ window.fetch = () => Promise.resolve({json: () => Promise.resolve([{ author: 'Wh
You should use `const` to create a `fetchMoreAuthors` function.
```js
assert.match(code, /const\s+fetchMoreAuthors\s*=\s*/)
const explorer = await __helpers.Explorer(code);
const { fetchMoreAuthors } = explorer.allFunctions;
assert.isTrue(fetchMoreAuthors?.toString().startsWith('const'));
```
`fetchMoreAuthors` should be a function.
Your `fetchMoreAuthors` variable should be a function.
```js
assert.isFunction(fetchMoreAuthors)
```
Your `fetchMoreAuthors` function should not take any parameter.
Your `fetchMoreAuthors` function should not take any parameters.
```js
assert.match(code, /const\s+fetchMoreAuthors\s*=\s*\(\s*\)\s*/)
const explorer = await __helpers.Explorer(code);
const { fetchMoreAuthors } = explorer.allFunctions;
assert.deepEqual(fetchMoreAuthors?.parameters.map((p) => p.toString()), []);
```
Your `fetchMoreAuthors` function should use arrow syntax.
Your `fetchMoreAuthors` function should use arrow function syntax and have an empty body.
```js
assert.match(code, /const\s+fetchMoreAuthors\s*=\s*\(\s*\)\s*=>\s*/)
```
Your `fetchMoreAuthors` function should be empty.
```js
assert.match(code, /const\s+fetchMoreAuthors\s*=\s*\(\s*\)\s*=>\s*\{\s*\}/)
const explorer = await __helpers.Explorer(code);
const { fetchMoreAuthors } = explorer.allFunctions;
const validExpressions = [
'const fetchMoreAuthors = () => {}',
'let fetchMoreAuthors = () => {}',
'var fetchMoreAuthors = () => {}'
];
assert.isTrue(
validExpressions.some((expression) => fetchMoreAuthors?.matches(expression))
);
```
# --seed--
@@ -7,7 +7,7 @@ dashedName: step-16
# --description--
Inside the `fetchMoreAuthors` function, set the `startingIndex` and `endingIndex` variables to `+= 8` each.
Inside the `fetchMoreAuthors` function, set the `startingIndex` and `endingIndex` variables to `+=8` each.
# --before-all--
@@ -33,14 +33,14 @@ const afterAdd = code.split("endingIndex += 8;")[1];
assert.match(afterAdd, /displayAuthors\(\s*authorDataArr\.slice\(/)
```
The first argument of your `slice()` method should be `startingIndex`.
Your first `slice()` argument should be `startingIndex`.
```js
const afterAdd = code.split("endingIndex += 8;")[1];
assert.match(afterAdd, /displayAuthors\(\s*authorDataArr\.slice\(\s*startingIndex/)
```
The second argument of your `slice()` method should be `endingIndex`.
Your second `slice()` argument should be `endingIndex`.
```js
const afterAdd = code.split("endingIndex += 8;")[1];
@@ -37,13 +37,13 @@ You should check if the length of the `bio` text is greater than `50`.
assert.match(code, /<p\s*class=("|')bio\1>\s*\$\{\s*bio\.length\s*>\s*50/)
```
If the `bio` text is greater than `50` characters, you should extract the first 50 characters with `slice()` and replace the rest with `"..."`. Don't forget that indexes are zero-based.
You should extract the first 50 characters with `slice()` and replace the rest with `"..."` if `bio` is greater than `50` characters. Don't forget that indexes are zero-based.
```js
assert.match(code, /<p\s*class\s*=\s*("|')bio\1\s*>\s*\$\{\s*bio\.length\s*>\s*50\s*\?\s*(?:bio\.slice\(\s*0\s*,\s*50\s*\)\s*\+\s*("|')\.\.\.\2|`\$\{\s*bio\.slice\(\s*0\s*,\s*50\s*\)\s*\}\.\.\.`)\s*:/);
```
If the `bio` text is less than 50 characters, use the `bio` text directly.
You should use the `bio` text directly if it is 50 characters or less.
```js
assert.match(code, /<p\s*class\s*=\s*("|')bio\1\s*>\s*\$\{\s*bio\.length\s*>\s*50\s*\?\s*(?:bio\.slice\(\s*0\s*,\s*50\s*\)\s*\+\s*("|')\.\.\.\2|`\$\{\s*bio\.slice\(\s*0\s*,\s*50\s*\)\s*\}\.\.\.`)\s*:\s*bio\s*\}\s*<\/p>/);
@@ -19,7 +19,7 @@ window.fetch = () => Promise.resolve({json: () => Promise.resolve([{ author: 'Wh
# --hints--
You should access the `style` property of `loadMoreBtn` with a dot notation.
You should access the `style` property of `loadMoreBtn` with dot notation.
```js
assert.match(code, /loadMoreBtn\.style/)
@@ -11,7 +11,7 @@ Now that your fCC Authors Page is fully functional, let's refactor it to improve
Recall that in order to use the `await` operator to wait for a function that returns a `Promise`, you need to wrap the function call in an `async` function (if it is not in the main body of a module).
Since your `fetch` call is not defined in either an asynchronous function nor in the main body of a module, you cannot use `await` before fixing that.
Since your `fetch` call is not defined in either an asynchronous function or the main body of a module, you cannot use `await` before fixing that.
Wrap the `fetch` statement and the entire sequence of chained then and catch methods as a whole in a new asynchronous arrow function called `initialFetch` which takes no arguments.
@@ -29,7 +29,7 @@ window.fetch = () => Promise.resolve({json: () => Promise.resolve([{ author: 'Wh
# --hints--
`initialFetch` should be a function.
Your `initialFetch` variable should be a function.
```js
assert.isFunction(initialFetch)
@@ -38,23 +38,28 @@ assert.isFunction(initialFetch)
You should use `const` to create an `initialFetch` function.
```js
assert.match(code, /const\s+initialFetch\s*=\s*/)
const explorer = await __helpers.Explorer(code);
const { initialFetch } = explorer.allFunctions;
assert.isTrue(initialFetch?.toString().startsWith('const'));
```
`initialFetch` should be an async function.
Your `initialFetch` variable should be an async function.
```js
assert.isFunction(initialFetch)
assert.match(code, /const\s+initialFetch\s*=\s*async\s*/)
const explorer = await __helpers.Explorer(code);
const { initialFetch } = explorer.allFunctions;
assert.include(initialFetch?.toString() ?? '', 'async');
```
Your `initialFetch` function should not take any parameter.
Your `initialFetch` function should not take any parameters.
```js
assert.match(code, /const\s+initialFetch\s*=\s*.*\s*\(\s*\)\s*/)
const explorer = await __helpers.Explorer(code);
const { initialFetch } = explorer.allFunctions;
assert.deepEqual(initialFetch?.parameters.map((p) => p.toString()), []);
```
Your `initialFetch` function should use arrow syntax.
Your `initialFetch` function should use arrow function syntax.
```js
assert.match(code, /const\s+initialFetch\s*=\s*.*\s*\(.*\)\s*=>\s*/)
@@ -40,7 +40,7 @@ You should assign the awaited result of `res.json()` to the `authorDataArr` vari
assert.match(code, /^\s*authorDataArr\s*=\s*await\s+res\.json\(\s*\)\s*;?/m)
```
`displayAuthors` should still be called as before
Your `displayAuthors` call should remain unchanged.
```js
assert.match(code, /^\s*displayAuthors\(\s*authorDataArr\.slice\(\s*startingIndex\s*,\s*endingIndex\s*\)\s*\)\s*;?/m)
@@ -174,7 +174,7 @@ const initialFetch = async () => {
.catch((err) => {
authorContainer.innerHTML = '<p class="error-msg">There was an error loading the authors</p>';
});
}
};
const fetchMoreAuthors = () => {
startingIndex += 8;
@@ -36,13 +36,13 @@ You should create a `try/catch` block
assert.match(code, /try\s*\{[\s\S]*?\}\s*catch\s*\([^)]*\)\s*\{/);
```
The `catch` should no longer be a chained method
Your `catch` should no longer be a chained method.
```js
assert.notMatch(code, /\.catch/);
```
The `try` block should contain the three statements that fetch the data, create the `json` and then display it.
Your `try` block should contain the three statements that fetch the data, create the `json`, and then display it.
```js
const tryBlockRegex =
@@ -68,7 +68,7 @@ assert.isTrue(jsonLineRegex.test(tryBlockContents));
assert.isTrue(displayLineRegex.test(tryBlockContents));
```
The fCC Authors Page should be rendering correctly
Your fCC Authors Page should render correctly.
```js
assert.equal(document.querySelector('.author-name').innerText, `Whoever`);
@@ -195,7 +195,7 @@ const initialFetch = async () => {
authorContainer.innerHTML = '<p class="error-msg">There was an error loading the authors</p>';
});
--fcc-editable-region--
}
};
const fetchMoreAuthors = () => {
startingIndex += 8;
@@ -344,7 +344,7 @@ const initialFetch = async () => {
} catch (err) {
authorContainer.innerHTML = '<p class="error-msg">There was an error loading the authors</p>';
}
}
};
const fetchMoreAuthors = () => {
startingIndex += 8;