chore(i8n,curriculum): processed translations (#41551)

Co-authored-by: Crowdin Bot <support+bot@crowdin.com>
This commit is contained in:
camperbot
2021-03-22 07:52:28 -06:00
committed by GitHub
parent 7215a6fa77
commit 7615ddf702
94 changed files with 1061 additions and 985 deletions

View File

@ -33,57 +33,49 @@ function functionName() {
assert(typeof reusableFunction === 'function');
```
`reusableFunction` 应该字符串 `Hi World` 输出到控制台
如果调用 `reusableFunction`应该在控制台输出字符串 `Hi World`
```js
assert(hiWorldWasLogged);
assert(testConsole());
```
定义 `reusableFunction` 之后记得调用它。
在定义 `reusableFunction` 之后,就应该调用它。
```js
assert(/^\s*reusableFunction\(\)\s*/m.test(code));
const functionStr = reusableFunction && __helpers.removeWhiteSpace(reusableFunction.toString());
const codeWithoutFunction = __helpers.removeWhiteSpace(code).replace(/reusableFunction\(\)\{/g, '');
assert(/reusableFunction\(\)/.test(codeWithoutFunction));
```
# --seed--
## --before-user-code--
```js
var logOutput = "";
var originalConsole = console;
var nativeLog = console.log;
var hiWorldWasLogged = false;
function capture() {
console.log = function (message) {
if(message === 'Hi World') hiWorldWasLogged = true;
if(message && message.trim) logOutput = message.trim();
if(nativeLog.apply) {
nativeLog.apply(originalConsole, arguments);
} else {
var nativeMsg = Array.prototype.slice.apply(arguments).join(' ');
nativeLog(nativeMsg);
}
};
}
function uncapture() {
console.log = nativeLog;
}
capture();
```
## --after-user-code--
```js
uncapture();
if (typeof reusableFunction !== "function") {
(function() { return "reusableFunction is not defined"; })();
} else {
(function() { return logOutput || "console.log never called"; })();
function testConsole() {
var logOutput = "";
var originalConsole = console;
var nativeLog = console.log;
var hiWorldWasLogged = false;
console.log = function (message) {
if(message === 'Hi World') {
console.warn(message)
hiWorldWasLogged = true;
}
if(message && message.trim) logOutput = message.trim();
if(nativeLog.apply) {
nativeLog.apply(originalConsole, arguments);
} else {
var nativeMsg = Array.prototype.slice.apply(arguments).join(' ');
nativeLog(nativeMsg);
}
};
reusableFunction();
console.log = nativeLog;
return hiWorldWasLogged;
}
```
## --seed-contents--

View File

@ -16,13 +16,15 @@ dashedName: add-id-attributes-to-bootstrap-elements
记住,可以这样给一个元素设置 id
`<div class="well" id="center-well">`
```html
<div class="well" id="center-well">
```
左边 well 的 id 设置`left-well`。 右边的 well 的 id 设置`right-well`
左边的块设置 id 为 `left-well`右边的块设置 id 为 `right-well`
# --hints--
左边 `well` 的 id 应`left-well`
左边 `well` 的 id 应为 `left-well`
```js
assert(
@ -31,7 +33,7 @@ assert(
);
```
右边的 `well` 的 id 应`right-well`
右边的 `well` 的 id 应为 `right-well`
```js
assert(

View File

@ -12,17 +12,19 @@ dashedName: center-text-with-bootstrap
记住:可以为一个元素添加多个 classes class 间通过空格分隔,就像这样:
`<h2 class="red-text text-center">your text</h2>`
```html
<h2 class="red-text text-center">your text</h2>
```
# --hints--
`h2` 元素应该通过 `text-center` class 使其居中显示
应使用 `text-center` class `h2` 元素居中。
```js
assert($('h2').hasClass('text-center'));
```
`h2` 元素应该包含 `red-text` class
`h2` 元素应具有 `red-text` class
```js
assert($('h2').hasClass('red-text'));

View File

@ -10,39 +10,43 @@ dashedName: create-a-block-element-bootstrap-button
一般情况下,`btn``btn-default` 两个 classes 修饰的 `button` 元素宽度与它包含的文本相同, 举个例子:
`<button class="btn btn-default">Submit</button>`
```html
<button class="btn btn-default">Submit</button>
```
这个按钮的宽度应该和文本`Submit` 的宽度相同。
这个按钮的宽度应该和文本 `Submit` 的宽度相同。
<button class='btn btn-default'>提交</button>
通过为按钮添加 class 属性 `btn-block` 使其成为块级元素,按钮会伸展并填满页面整个水平空间,后续的元素会流到这个块级元素的下方,即 "另起一行"。
通过为按钮添加 class 属性 `btn-block` 使其成为块级元素,按钮会伸展并填满页面整个水平空间,后续的元素会流到这个块级元素的下方,即 "另起一行"。
`<button class="btn btn-default btn-block">Submit</button>`
```html
<button class="btn btn-default btn-block">Submit</button>
```
这个按钮会 100% 占满所有的可用宽度。
<button class='btn btn-default btn-block'>提交</button>
记住这些按钮仍然需要 `btn` 这个 class。
注意,这些按钮仍然需要 `btn` 这个 class。
添加 Bootstrap 的 `btn-block` class 到刚创建的 Bootstrap 按钮上吧
给刚创建的 Bootstrap 按钮添加 Bootstrap 的 `btn-block` class。
# --hints--
按钮的 class 属性应该仍然包含 `btn``btn-default`
按钮仍然应该有 `btn``btn-default` class
```js
assert($('button').hasClass('btn') && $('button').hasClass('btn-default'));
```
按钮的 class 属性应该包含 `btn-block`
按钮应该有 `btn-block` class
```js
assert($('button').hasClass('btn-block'));
```
确保所有 `button` 元素都有一个闭合标签。
所有 `button` 元素都应该有闭合标签。
```js
assert(

View File

@ -22,7 +22,9 @@ dashedName: use-a-span-to-target-inline-elements
对含有文本 `Top 3 things cats hate``p` 元素这样处理:
`<p>Top 3 things cats <span class="text-danger">hate:</span></p>`
```html
<p>Top 3 things cats <span class="text-danger">hate:</span></p>
```
# --hints--
@ -32,7 +34,7 @@ dashedName: use-a-span-to-target-inline-elements
assert($('p span') && $('p span').length > 0);
```
`span` 元素应该只包括 `love` 文本
`span` 元素应该有文本 `love`
```js
assert(
@ -44,13 +46,13 @@ assert(
);
```
`span` 元素应该`text-danger` class。
`span` 元素应该有 `text-danger` class。
```js
assert($('span').hasClass('text-danger'));
```
确保 `span` 元素有一个闭合标签。
`span` 元素应该有一个闭合标签。
```js
assert(

View File

@ -16,21 +16,23 @@ Bootstrap 会根据屏幕大小来动态调整 HTML 元素的大小————
任何 Web 应用,都可以通过添加如下代码到 HTML 顶部来引入 Bootstrap 。
`<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous"/>`
```html
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous"/>
```
在该类课程中,我们已经提前帮你把相应代码添加到了页面中。 注意使用 `>` 或者 `/>` 两种方式闭合 `link` 标签都是可行的。
不过在这里,已经预先为此页面添加了上述代码。 注意使用 `>` 或者 `/>` 两种方式闭合 `link` 标签都是可行的。
首先,我们应该所有 HTML 标签放在 class 为 `container-fluid``div` 元素内(除了 `link` 标签和 `style` 元素)
首先,我们应该所有 HTML `link` 标签和 `style` 元素除外)嵌套在带有 `container-fluid` class`div` 元素里面
# --hints--
`div` 元素的 class 属性值应该 `container-fluid`
`div` 元素应该 `container-fluid` class
```js
assert($('div').hasClass('container-fluid'));
```
确保该 `div` 元素有闭合标签.
`div` 元素应该有结束标签
```js
assert(
@ -40,7 +42,7 @@ assert(
);
```
确保已经将闭合 `style` 标签后所有 HTML 元素内嵌`.container-fluid` 元素中
`style` 结束标签后面的所有 HTML 元素都应该被嵌套`.container-fluid` 里面
```js
assert($('.container-fluid').children().length >= 8);

View File

@ -14,15 +14,17 @@ jQuery 有一个 `.html()` 函数,能用其在标签里添加 HTML 标签和
下面是重写并强调标题文本的代码:
`$("h3").html("<em>jQuery Playground</em>");`
```js
$("h3").html("<em>jQuery Playground</em>");
```
jQuery 还有一个类似的函数 `.text()` 可以在不添加标签的前提下改变标签内的文本。 换言之,这个函数不会识别传入的任何 HTML 标,而会把它当做想要替换现有内容的文本。
jQuery 还有一个类似的函数 `.text()`可以在不添加标签的前提下改变标签内的文本。 换句话说,这个函数不会评估传递给它的任何 HTML 标,而是将其视为要替换现有内容的文本。
给 id 为 `target4` 的按钮的文本添加强调效果。
查看[关于 &lt;em> 的文章](https://www.freecodecamp.org/news/html-elements-explained-what-are-html-tags/#em-element)来了解更多 `<i>``<em>` 的区别和用法。
查看这篇[关于 &lt;em> 的文章](https://www.freecodecamp.org/news/html-elements-explained-what-are-html-tags/#em-element)来了解更多 `<i>``<em>` 的区别和用法。
注意,`<i>` 标签虽然传统上用来强调文本,但此后常用作图标的标签。 `<em>` 标签作为强调标签现在已被广泛接受。 使用这两个标签中的任一个都可以完成本次挑战。
注意,`<i>` 标签虽然传统上用来强调文本,但此后常用作图标的标签。 `<em>` 标签作为强调标签现在已被广泛接受。 可以使用任意一种完成这个挑战。
# --hints--

View File

@ -17,23 +17,25 @@ jQuery 有一个 `.css()` 方法,能改变标签的 CSS。
下面的代码效果是把颜色变蓝:
`$("#target1").css("color", "blue");`
```js
$("#target1").css("color", "blue");
```
这与通常的 CSS 声明略有不同,因为这个 CSS 属性和它的值在英文引号里,并且它们用逗号而不是冒号间隔开。
删除 jQuery 选择器,留下空的 `document ready function`
删除 jQuery 选择器,留下一个空的 `document ready function`
选择 `target1` 并将其颜色为红色red
选择 `target1`并将其颜色更改为红色。
# --hints--
`target1` 标签应该有红色文本。
`target1` 元素应该有红色文本。
```js
assert($('#target1').css('color') === 'rgb(255, 0, 0)');
```
应该仅用 jQuery 给标签添加类
应该仅用 jQuery 给元素添加这些 class
```js
assert(!code.match(/class.*animated/g));

View File

@ -14,27 +14,29 @@ jQuery 有一个 `clone()` 方法,可以复制标签。
例如,如果想把 `target2``left-well` 复制到 `right-well`,可以设置如下:
`$("#target2").clone().appendTo("#right-well");`
```js
$("#target2").clone().appendTo("#right-well");
```
是否注意到这两个 jQuery 方法连在一起了? 这被称为 <dfn>链式调用function chaining</dfn>,是一种用 jQuery 实现效果的简便方法。
是否注意到这两个 jQuery 函数连在一起了? 这被称为<dfn>链式调用function chaining</dfn>,是一种用 jQuery 实现效果的简便方法。
克隆 `target5` 标签并附加到 `left-well`
克隆 `target5` 元素,并将其附加到 `left-well`
# --hints--
`target5` 标签应该在 `right-well`
`target5` 元素应该在 `right-well` 里面
```js
assert($('#right-well').children('#target5').length > 0);
```
应该克隆 `target5` 标签并放在 `left-well`
应该克隆 `target5` 元素,并放在 `left-well` 里面
```js
assert($('#left-well').children('#target5').length > 0);
```
应该仅用 jQuery 移动这些标签
应该仅用 jQuery 移动这些元素
```js
assert(!code.match(/class.*animated/g));

View File

@ -16,13 +16,15 @@ jQuery 有一个 `.prop()` 方法,可以用其调整标签的属性。
下面是禁用所有的按钮的代码:
`$("button").prop("disabled", true);`
```js
$("button").prop("disabled", true);
```
禁用 `target1` 按钮。
禁用 `target1` 按钮。
# --hints--
应该禁用 `target1` 按钮。
`target1` 按钮应该被禁用
```js
assert(
@ -38,7 +40,7 @@ assert(
assert($('#target2') && !$('#target2').prop('disabled'));
```
应该仅用 jQuery 更改元素属性
应该仅用 jQuery 给元素添加这些 class
```js
assert(!code.match(/disabled[^<]*>/g));

View File

@ -15,25 +15,27 @@ dashedName: remove-classes-from-an-element-with-jquery
下面是为指定按钮执行上面的操作的代码:
`$("#target2").removeClass("btn-default");`
```js
$("#target2").removeClass("btn-default");
```
请把所有 `button` 标签`btn-default` 移除。
请把所有 `button` 元素`btn-default` class 移除。
# --hints--
应该移除所有 `button` 标签 `btn-default` 属性
应该移除所有 `button` 元素 `btn-default` class
```js
assert($('.btn-default').length === 0);
```
应该仅用 jQuery 从标签中移除
应该仅用 jQuery 从元素中移除 class
```js
assert(code.match(/btn btn-default/g));
```
应该仅移除 `btn-default`
应该仅移除 `btn-default` class
```js
assert(

View File

@ -19,9 +19,11 @@ jQuery 可以用 CSS 选择器CSS Selectors选取标签。 `target:nth-chi
下面的代码展示了给每个区域well的第 3 个标签设置弹跳bounce动画效果
`$(".target:nth-child(3)").addClass("animated bounce");`
```js
$(".target:nth-child(3)").addClass("animated bounce");
```
给 well 元素的第二个子元素添加弹跳bounce动画效果。 必须选择具有 `target` class 的元素。
给 well 元素的第二个子元素添加弹跳bounce动画效果。 必须选择具有 `target` class 的元素子项
# --hints--
@ -34,19 +36,19 @@ assert(
);
```
应该仅两个标签有弹跳bounce动画效果。
应该仅两个元素有弹跳bounce动画效果。
```js
assert($('.animated.bounce').length === 2);
```
应该用 `:nth-child()` 选择器修改这些标签
应该使`:nth-child()` 选择器修改这些元素
```js
assert(code.match(/\:nth-child\(/g));
```
应该仅用 jQuery 给标签添加类
应该仅用 jQuery 给元素添加 class
```js
assert(

View File

@ -23,17 +23,19 @@ jQuery 的 `.addClass()` 方法用来给标签添加类。
例如,在 `document ready function` 中添加下面的代码,使所有类为 `text-primary` 的标签抖动:
`$(".text-primary").addClass("animated shake");`
```js
$(".text-primary").addClass("animated shake");
```
# --hints--
应该用 jQuery 的 `addClass()` 方法给所有 class 为 `well`标签添加 `animated``shake`
应该用 jQuery 的 `addClass()` 方法给所有 class 为 `well`元素添加 `animated``shake` class
```js
assert($('.well').hasClass('animated') && $('.well').hasClass('shake'));
```
应该仅用 jQuery 给标签添加 class。
应该仅用 jQuery 给元素添加这些 class。
```js
assert(!code.match(/class\.\*animated/g));

View File

@ -21,17 +21,19 @@ dashedName: target-elements-by-id-using-jquery
下面的代码的效果是使 id 为 `target6``button` 标签淡出:
`$("#target6").addClass("animated fadeOut")`.
```js
$("#target6").addClass("animated fadeOut");
```
# --hints--
应该用 jQuery 的 `addClass()` 方法给 `id``target3``button` 标签添加 `animated`
应该选择 `id``target3``button` 元素,使用 jQuery 的 `addClass()` 函数给它添加 `animated` class
```js
assert($('#target3').hasClass('animated'));
```
应该用 jQuery 的 `addClass()` 方法给 id 为 `target3` 的标签的类添加 `fadeOut`
应该选中 id 为 `target3` 的元素,使用 jQuery 的 `addClass()` 函数给它添加 `fadeOut` class
```js
assert(
@ -40,7 +42,7 @@ assert(
);
```
应该仅用 jQuery 给标签设置类
应该仅用 jQuery 给元素添加这些 class
```js
assert(!code.match(/class.*animated/g));

View File

@ -17,13 +17,15 @@ dashedName: target-even-elements-using-jquery
下面的代码展示了选取所有 `target` class 元素的奇数元素并设置 sheke 效果:
`$(".target:odd").addClass("animated shake");`
```js
$(".target:odd").addClass("animated shake");
```
尝试选取所有 `target` class 元素的偶数元素并给它们设置 `animated``shake` class。 要考虑到**偶even**指的是标签位置编号是从 0 开始的
尝试选取所有 `target` class 元素的偶数元素并给它们设置 `animated``shake` class。 请记住, **偶数**指的是基于零系统的元素的位置
# --hints--
所有的 `target` 标签应该抖动。
所有的偶数位置上的 `target` 元素都应该抖动。
```js
assert(
@ -31,13 +33,13 @@ assert(
);
```
应该用 `:even` 选择器修改这些标签
应该使`:even` 选择器修改这些元素
```js
assert(code.match(/\:even/g));
```
应该仅用 jQuery 给标签添加类
应该仅用 jQuery 给元素添加 class
```js
assert(

View File

@ -19,19 +19,21 @@ jQuery 通常选取并操作带有<dfn>选择器selector</dfn>的 HTML 标
比如,想要给 `button` 元素添加跳跃效果。 只需要在 document ready 函数内添加如下代码:
`$("button").addClass("animated bounce");`
```js
$("button").addClass("animated bounce");
```
请注意,已经在后台引入了 jQuery 库和 Animate.css 库,所以可以在编辑器里直接使用 jQuery 和动画。 因此,只需要通过 jQuery 给 `button` 元素添加 `bounce` 类就可以了
请注意,我们已经在后台引入了 jQuery 库和 Animate.css 库,所以可以在编辑器里直接使用它们。 你将使用 jQuery 将 Animate.css `bounce` class 应用于 `button` 元素
# --hints--
应该用 jQuery 的 `addClass()` 方法`button` 标签添加 `animated``bounce`
应该用 jQuery 的 `addClass()` 函数`button` 元素添加 `animated``bounce` class
```js
assert($('button').hasClass('animated') && $('button').hasClass('bounce'));
```
应该仅用 jQuery 给标签添加这些 class。
应该仅用 jQuery 给元素添加 class。
```js
assert(!code.match(/class.*animated/g));

View File

@ -14,27 +14,29 @@ jQuery 有一个 `children()` 方法,可以访问被选取标签的子标签
下面的代码展示了用 `children()` 方法把 `left-well` 标签的子标签的颜色设置成 `blue`(蓝色):
`$("#left-well").children().css("color", "blue")`
```js
$("#left-well").children().css("color", "blue")
```
# --instructions--
`right-well` 标签的所有子标签颜色设置橙色orange
`right-well` 元素的所有子元素设置橙色orange
# --hints--
`#right-well` 所有的子标签文本应该橙色。
`#right-well` 所有子元素应该橙色文本
```js
assert($('#right-well').children().css('color') === 'rgb(255, 165, 0)');
```
应该用 `children()` 方法修改标签
应该用 `children()` 函数修改这些元素
```js
assert(code.match(/\.children\(\)\.css/g));
```
应该仅用 jQuery 给标签添加
应该仅用 jQuery 给标签添加 class
```js
assert(code.match(/<div class="well" id="right-well">/g));

View File

@ -16,13 +16,15 @@ jQuery 有一个 `parent()` 方法,可以访问被选取标签的父标签。
下面的代码展示了使用 `parent()` 方法把 `left-well` 标签的父标签背景色设置成蓝色blue
`$("#left-well").parent().css("background-color", "blue")`
```js
$("#left-well").parent().css("background-color", "blue")
```
`#target1` 标签的父标签背景色设置成红色red
`#target1` 元素的父元素背景色设置成红色red
# --hints--
`left-well` 标签应该有红色的背景。
`left-well` 元素应该有红色的背景。
```js
assert(
@ -33,13 +35,13 @@ assert(
);
```
应该用 `.parent()` 方法修改该标签
应该用 `.parent()` 函数修改该元素
```js
assert(code.match(/\.parent\s*\(\s*\)\s*\.css/g));
```
应该在 `#target1` 标签上调用 `.parent()` 方法。
应该在 `#target1` 元素上调用 `.parent()` 方法。
```js
assert(
@ -47,7 +49,7 @@ assert(
);
```
应该仅用 jQuery 给标签添加类
应该仅用 jQuery 给元素添加 class
```js
assert(code.match(/<div class="well" id="left-well">/g));

View File

@ -14,19 +14,21 @@ jQuery 有一个 `appendTo()` 方法,可以选取 HTML 标签并将其添加
例如,如果要把 `target4` 从 right well 移到 left well可以设置如下
`$("#target4").appendTo("#left-well");`
```js
$("#target4").appendTo("#left-well");
```
`target2` 标签`left-well` 移动到 `right-well`
`target2` 元素`left-well` 移动到 `right-well`
# --hints--
`target2` 标签不应该在 `left-well` 内。
`target2` 元素不应该在 `left-well` 内。
```js
assert($('#left-well').children('#target2').length === 0);
```
`target2` 标签应该在 `right-well` 内。
`target2` 元素应该在 `right-well` 内。
```js
assert($('#right-well').children('#target2').length > 0);

View File

@ -12,13 +12,15 @@ dashedName: connect-redux-to-react
为了使用此方法,需要传入函数参数并在调用时传入组件。 这种语法有些不寻常,如下所示:
`connect(mapStateToProps, mapDispatchToProps)(MyComponent)`
```js
connect(mapStateToProps, mapDispatchToProps)(MyComponent)
```
**注意:** 如果要省略 `connect` 方法中的某个参数,则应当用 `null` 替换这个参数。
**注意:**如果要省略 `connect` 方法中的某个参数,则应当用 `null` 替换这个参数。
# --instructions--
编辑器上有两个函数:`mapStateToProps()``mapDispatchToProps()`,还有一个叫 `Presentational` 的 React 组件。 用 `ReactRedux` 全局对象中的 `connect` 方法将此组件连接到 Redux并立即在 `Presentational` 组件调用结果赋值给一个名为 `ConnectedComponent` 的代表已连接组件的新 `const`。 大功告成,已成功把 React 连接到 Redux 尝试更改任何一个 `connect` 参数为 `null` 并观察测试结果。
代码编辑器具有 `mapStateToProps()``mapDispatchToProps()` 函数,以及一个名为 `Presentational` React 组件。 使`ReactRedux` 全局对象中的 `connect` 方法将此组件连接到 Redux并立即在 `Presentational` 组件调用它。 将结果赋值给名为 `ConnectedComponent` 的新 `const`,表示连接的组件。 就是这样,现在你已经连接到 Redux 尝试 `connect` 参数更改`null`并观察测试结果。
# --hints--

View File

@ -14,17 +14,21 @@ dashedName: introducing-inline-styles
将内联样式应用于 JSX 元素,类似于在 HTML 中的操作方式,但有一些 JSX 差异。 以下是 HTML 中内联样式的示例:
`<div style="color: yellow; font-size: 16px">Mellow Yellow</div>`
```jsx
<div style="color: yellow; font-size: 16px">Mellow Yellow</div>
```
JSX 元素使用 `style` 属性,但是于 JSX 的编译方式,不能将值设置为 `string`(字符串)。 相反,你应将其设置为 JavaScript `object`(对象)。 这里有一个例子
JSX 元素使用 `style` 属性,但是于 JSX 的编译方式,不能将值设置为 `string`(字符串)。 相反,你应将其设置为等于JavaScript `object` 。 如下所示
`<div style={{color: "yellow", fontSize: 16}}>Mellow Yellow</div>`
```jsx
<div style={{color: "yellow", fontSize: 16}}>Mellow Yellow</div>
```
注意如何驼峰拼写 `fontSize` 属性? 这是因为 React 不接受下划线分隔的样式对象。 React 将在 HTML 中编译为正确的属性名称。
注意如何驼峰拼写 `fontSize` 属性了吗 这是因为 React 不接受样式对象中的 kebab-case 键。 React 将在 HTML 中为应用正确的属性名称。
# --instructions--
在代码编辑器 `div` 添加一个 `style` 属性,使文本颜色为红色,字体大小为 `72px`
在代码编辑器中给 `div` 添加一个 `style` 属性,文本颜色设置为红色,字体大小设置`72px`
请注意,可以选择将字体大小设置为数字,省略单位 `px`,或者将其写为 `72px`

View File

@ -10,17 +10,19 @@ dashedName: use--for-a-more-concise-conditional
`if/else` 语句在上一次挑战中是有效的,但是有一种更简洁的方法可以达到同样的结果。 假设正在跟踪组件中的几个条件,并且希望根据这些条件中的每一个来渲染不同的元素。 如果你写了很多 `else if` 语句来返回稍微不同的 UI你可能会写很多重复代码这就留下了出错的空间。 相反,你可以使用 `&&` 逻辑运算符以更简洁的方式执行条件逻辑。 这是完全可行的,因为你希望检查条件是否为 `true`。如果是,则返回一些标记。 这里有一个例子:
`{condition && <p>markup</p>}`
```jsx
{condition && <p>markup</p>}
```
如果 `condition``true`,则返回标记。 如果 condition `false`,操作将在判断 `condition` 后立即返回 `false`,并且不返回任何内容。 可以将这些语句直接包含在 JSX 中,并通过在每个条件后面写 `&&` 来将多个条件串在一起。 这允许在 `render()` 方法中处理更复杂的条件逻辑,而无需重复大量代码。
如果 `condition``true`,则返回标记。 如果条件`false` ,则在评估 `condition`操作将立即返回 `false`,并且不返回任何内容。 可以将这些语句直接包含在 JSX 中,并通过在每个条件后面写 `&&` 来将多个条件串在一起。 这允许`render()` 方法中处理更复杂的条件逻辑,而无需重复大量代码。
# --instructions--
再来看看前面的示例,`h1` 还是在 `display``true`渲染,但使用 `&&` 逻辑运算符代替 `if/else` 语句。
再来看看前面的示例,`h1` 还是在 `display``true` 时渲染,但使用 `&&` 逻辑运算符代替 `if/else` 语句。
# --hints--
`MyComponent` 应该存在并渲染。
`MyComponent` 应该存在并渲染。
```js
assert(
@ -31,7 +33,7 @@ assert(
);
```
`display` 被设置为 `true` 时,`div``button``h1` 标签应该渲染。
`display` 被设置为 `true` 时,`div``button``h1` 标签应该渲染。
```js
async () => {
@ -52,7 +54,7 @@ async () => {
};
```
`display` 被设置为 `false` 时,只有 `div``button` 应该渲染。
`display` 被设置为 `false` 时,只有 `div``button` 应该渲染。
```js
async () => {

View File

@ -10,11 +10,13 @@ dashedName: use-array-filter-to-dynamically-filter-an-array
`map` 数组方法是一个强大的工具,在使用 React 时经常使用。 与 `map` 相关的另一种方法是 `filter`,它根据条件过滤数组的内容,然后返回一个新数组。 例如,如果有一个 users 数组,每个数组元素都有一个可以设置为 `true``false``online` 属性,可以这样只过滤那些在线的用户:
`let onlineUsers = users.filter(user => user.online);`
```js
let onlineUsers = users.filter(user => user.online);
```
# --instructions--
在代码编辑器中,`MyComponent``state` 由一个 users 数组初始化。 有些用户在线,有些则不在线。 过滤数组,只看到在线用户。 为此,首先使用 `filter` 返回一个新数组,该数组只包含 `online` 属性为 `true` 的用户。 然后,在 `renderOnline` 变量中,映射经过过滤的数组,并为每个用户返回一个包含它们 `username` 文本的 `li` 元素。 确保像上一个挑战一样包含一个独特`key`
在代码编辑器中,`MyComponent``state` 被初始化为一个用户数组。 有些用户在线,有些则没有。 过滤数组,以便只查看在线用户。 要执行此操作,请首先使用 `filter` 返回包含 `online` 属性为 `true` 的用户的新数组。 然后,在 `renderOnline` 变量中,映射过滤的数组,并为包含其 `username` 文本的每个用户返回 `li` 元素。 确保包含一个唯一`key` ,就像上一个挑战一样
# --hints--
@ -38,7 +40,7 @@ assert(
);
```
`MyComponent` 应该返回一个 `div`、一个 `h1` 和一个包含 `li` 元素无序列表,该列表用于展示在线状态为 `true`每个用户。
`MyComponent` 应该返回一个 `div`、一个 `h1` 元素,和一个包含 `li` 元素无序列表,该列表用于展示在线状态为 `true`所有用户。
```js
(() => {
@ -81,7 +83,7 @@ assert(
})();
```
`MyComponent` 应该渲染包含每个在线用户的 `username``li` 元素。
`MyComponent` 应该渲染包含所有在线用户的 `username``li` 元素。
```js
(() => {

View File

@ -12,15 +12,17 @@ React 提供了有用的类型检查特性,以验证组件是否接收了正
当提前知道 prop 的类型时,最佳实践是设置其 `propTypes`。 可以为组件定义 `propTypes` 属性,方法与定义 `defaultProps` 相同。 这样做将检查给定键的 prop 是否是给定类型。 这里有一个示例,表示名为 `handleClick` 的 prop 应为 `function` 类型:
`MyComponent.propTypes = { handleClick: PropTypes.func.isRequired }`
```js
MyComponent.propTypes = { handleClick: PropTypes.func.isRequired }
```
在上面的示例中,`PropTypes.func` 部分检查 `handleClick` 是否为函数。 添加 `isRequired` 是为了告诉 React `handleClick` 是该组件的必需属性。 如果未提供该 prop将看到警告信息。 另请注意`func` `function`。 在 7 种 JavaScript 基本类型中,`function``boolean`(写为 `bool`)是仅有的使用异常拼写的两种类型。 除了基本类型,还有其类型可用。 例如,可以检查 prop 是否为 React 组件, 请参阅[文档](https://reactjs.org/docs/jsx-in-depth.html#specifying-the-react-element-type)以获取所有选项。
在上面的示例中,`PropTypes.func` 部分检查 `handleClick` 是否为函数。 添加 `isRequired`告诉 React `handleClick` 是该组件的必需属性。 如果没有那个属性,将出现警告。 还要注意 `func` `function` 。 在 7 种 JavaScript 原语类型中, `function``boolean` (写为 `bool` )是唯一使用异常拼写的两种类型。 除了原始类型,还有其类型可用。 例如,可以检查 prop 是否为 React 元素。 请参阅[文档](https://reactjs.org/docs/jsx-in-depth.html#specifying-the-react-element-type)以获取所有选项。
**注意:** 在 React v15.5.0 版本中, `PropTypes` 可以从 React 中单独引入,例如: `import PropTypes from 'prop-types';`
**注意:**在 React v15.5.0 中, `PropTypes` 可以从 React 中单独引入,例如:`import PropTypes from 'prop-types';`
# --instructions--
`Items` 组件定义 `propTypes`,要求 `quantity` 作为 prop并验证它是 `number` 类型。
`Items` 组件定义 `propTypes`要求 `quantity` 作为 prop并验证它是否为 `number` 类型。
# --hints--

View File

@ -10,17 +10,19 @@ dashedName: copy-an-object-with-object-assign
最后几个挑战适用于数组,但是当状态是 `object` 时,有一些方法可以实现状态不变性。 处理对象的一个常用的方法是 `Object.assign()``Object.assign()` 获取目标对象和源对象,并将源对象中的属性映射到目标对象。 任何匹配的属性都会被源对象中的属性覆盖。 通常用于通过传递一个空对象作为第一个参数,然后是要用复制的对象来制作对象的浅表副本。 这是一个例子:
`const newObject = Object.assign({}, obj1, obj2);`
```js
const newObject = Object.assign({}, obj1, obj2);
```
这会创建 `newObject` 作为新的 `object`,其中包含 `obj1``obj2` 中当前存在的属性。
# --instructions--
Redux 状态和 action 被修改为处理 `state``object`。 编辑代码以返回一个新的 `state` 对象,用于含有 `ONLINE` 类型的 action ,它`status` 属性设置为字符串 `online`。 尝试使用 `Object.assign()` 来完成挑战。
Redux state 和 actions 被修改为处理 `state``object` 。 编辑代码,为类型为 `ONLINE` 的 actions 返回一个新的 `state` 对象,这个类型`status` 属性设置为 `online` 字符串。 尝试使用 `Object.assign()` 来完成挑战。
# --hints--
Redux store 应该存在并使用与第 1 行声明的 `defaultState` 对象相同的状态进行初始化。
Redux store 应该存在并使用与第行声明的 `defaultState` 对象相同的状态进行初始化。
```js
assert(
@ -43,7 +45,7 @@ assert(
assert(typeof wakeUp === 'function' && typeof immutableReducer === 'function');
```
dispatch 一个类型为 `ONLINE` 的 action 应该将状态 `status` 更新为 `online`,并且不应该改变状态。
调用一个类型为 `ONLINE` 的 action应该将状态中的 `status` 更新为 `online`,并且不应该改变状态。
```js
assert(

View File

@ -10,9 +10,11 @@ dashedName: use-the-spread-operator-on-arrays
ES6 中有助于在 Redux 中强制执行状态不变性的一个解决方案是扩展运算符:`...`。 扩展运算符具有很多的应用,其中一种非常适合通过一个已有的数组生成一个新数组。 这是相对较新的但常用的语法。 例如,如果你有一个数组 `myArray` 并写:
`let newArray = [...myArray];`
```js
let newArray = [...myArray];
```
`newArray` 现在是 `myArray` 的克隆。 两个数组仍然在内存中单独存在。 如果你执行像 `newArray.push(5)` 这样的代码,`myArray` 不会改变。 `...` 有效将 `myArray` 中的值 *展开*到一个新数组中。 要克隆数组但在新数组中添加其他值,可以编写 `[...myArray, 'new value']`。 这将返回一个由 `myArray` 中的值和字符串 `new value` (作为最后一个值)组成的新数组。 扩展语法可以像这样在数组组合中多次使用,但重要的是要注意它只做一个浅拷贝。 就是说,它只为一维数组提供不可变的数组操作。
`newArray` 现在是 `myArray` 的克隆。 两个数组仍然分别存在于内存中。 如果你执行像 `newArray.push(5)` 这样的变异, `myArray` 不会改变。 `...` 有效将 `myArray` 中的值*展开*到一个新数组中。 要克隆数组但在新数组中添加其他值,可以编写 `[...myArray, 'new value']`。 这将返回一个由 `myArray` 中的值和字符串 `new value`(作为最后一个值)组成的新数组。 扩展语法可以像这样在数组组合中多次使用,但重要的是要注意它只是生成数组的浅拷贝副本就是说,它只为一维数组提供不可变的数组操作。
# --instructions--
@ -20,7 +22,7 @@ ES6 中有助于在 Redux 中强制执行状态不变性的一个解决方案是
# --hints--
Redux store 应该在代码编辑器中存在并使用 `["Do not mutate state!"]` 进行状态初始化。
Redux store 应该在代码编辑器中存在并使用 `["Do not mutate state!"]` 进行状态初始化。
```js
assert(
@ -34,13 +36,13 @@ assert(
);
```
`addToDo``immutableReducer`都应该是一个函数。
`addToDo``immutableReducer` 都应该是函数。
```js
assert(typeof addToDo === 'function' && typeof immutableReducer === 'function');
```
在 Redux store 上 dispatch 一个类型为`ADD_TO_DO` aciton 应该添加一个`todo`项,并且不应该改变 state。
在 Redux store 上 dispatch 一个类型为 `ADD_TO_DO` aciton应该添加一个 `todo` 项,并且不应该改变 state。
```js
assert(

View File

@ -1,6 +1,6 @@
---
id: 589fc832f9fc0f352b528e78
title: Announce New Users
title: 用户公告
challengeType: 2
forumTopicId: 301546
dashedName: announce-new-users
@ -8,9 +8,9 @@ dashedName: announce-new-users
# --description--
Many chat rooms are able to announce when a user connects or disconnects and then display that to all of the connected users in the chat. Seeing as though you already are emitting an event on connect and disconnect, you will just have to modify this event to support such a feature. The most logical way of doing so is sending 3 pieces of data with the event: the name of the user who connected/disconnected, the current user count, and if that name connected or disconnected.
许多聊天室都有这个功能:所有已连接到服务器的在线用户都会看到有人加入或退出的提醒。 我们已经写好了处理连接和断开事件的代码,只要对这个方法稍作修改就可以实现这个功能。 在事件中,我们需要发送这三条信息:连接或断开的用户名、当前用户数量、事件类型(即需要知道用户究竟是连接还是断开)。
Change the event name to `'user'`, and pass an object along containing the fields 'name', 'currentUsers', and 'connected' (to be `true` in case of connection, or `false` for disconnection of the user sent). Be sure to change both 'user count' events and set the disconnect one to send `false` for the field 'connected' instead of `true` like the event emitted on connect.
请将事件名称更改为 `'user'`,其中应包含如下字段:'name''currentUsers''connected'(布尔值,连接上即为 `true`,断开则是 `false`)。 请务必更改两个 user count 事件,设置 disconnect 事件向 connected 字段发送 `false` ,而不是像 connect 事件一样发送 `true`
```js
io.emit('user', {
@ -20,9 +20,9 @@ io.emit('user', {
});
```
Now your client will have all the necessary information to correctly display the current user count and announce when a user connects or disconnects! To handle this event on the client side we should listen for `'user'`, then update the current user count by using jQuery to change the text of `#num-users` to `'{NUMBER} users online'`, as well as append a `<li>` to the unordered list with id `messages` with `'{NAME} has {joined/left} the chat.'`.
现在客户端已具备足够的信息,来显示当前用户数,并在用户连接或断开连接时通知! 接下来我们需要在客户端监听 `'user'` 事件,然后用 jQuery 把 `#num-users` 节点的文本内容更新为 `'{NUMBER} users online'`。 同时,我们需要为无序列表添加一个 id 为 `messages` 且带有 `'{NAME} has {joined/left} the chat.'` 文本的 `<li>`
An implementation of this could look like the following:
实现如下:
```js
socket.on('user', data => {
@ -34,11 +34,11 @@ socket.on('user', data => {
});
```
Submit your page when you think you've got it right. If you're running into errors, you can check out the project completed up to this point [here](https://gist.github.com/camperbot/bf95a0f74b756cf0771cd62c087b8286).
完成上述要求后,你可以在下方提交你的页面链接。 如果你遇到了问题,可以参考 [这里](https://gist.github.com/camperbot/bf95a0f74b756cf0771cd62c087b8286) 的答案。
# --hints--
Event `'user'` should be emitted with name, currentUsers, and connected.
事件 `'user'` 应该包含,name currentUsers connected
```js
(getUserInput) =>
@ -56,7 +56,7 @@ Event `'user'` should be emitted with name, currentUsers, and connected.
);
```
Client should properly handle and display the new data from event `'user'`.
客户端应处理和显示 `'user'` 中的新数据。
```js
(getUserInput) =>

View File

@ -1,6 +1,6 @@
---
id: 5895f70df9fc0f352b528e68
title: Authentication Strategies
title: 身份验证策略
challengeType: 2
forumTopicId: 301547
dashedName: authentication-strategies
@ -8,11 +8,11 @@ dashedName: authentication-strategies
# --description--
A strategy is a way of authenticating a user. You can use a strategy for allowing users to authenticate based on locally saved information (if you have them register first) or from a variety of providers such as Google or GitHub. For this project, we will set up a local strategy. To see a list of the hundreds of strategies, visit Passport's site [here](http://passportjs.org/).
策略是认证用户的一种方式。 如果你让用户在注册时填写了用户信息,那你就可以基于这些信息进行验证。或者也可以引入第三方登录,如 Google 或者 Github。 对于这个项目的验证策略,我们会采用自己搭建的方式完成。 可以[点击这里](http://passportjs.org/)访问 Passport 网站,查看数以百计的策略。
Add `passport-local` as a dependency and add it to your server as follows: `const LocalStrategy = require('passport-local');`
引入 `passport-local` 作为依赖,然后将它添加到服务器,就像这样:`const LocalStrategy = require('passport-local');`
Now you will have to tell passport to **use** an instantiated LocalStrategy object with a few settings defined. Make sure this (as well as everything from this point on) is encapsulated in the database connection since it relies on it!
然后,需要让 passport **使用**一个实例化的 LocalStrategy 对象,这个对象的一些设置已完成。 请注意,接下来的所有代码都应写在连接数据库的回调中,因为它们的执行都依赖数据库。
```js
passport.use(new LocalStrategy(
@ -28,17 +28,17 @@ passport.use(new LocalStrategy(
));
```
This is defining the process to use when we try to authenticate someone locally. First, it tries to find a user in our database with the username entered, then it checks for the password to match, then finally, if no errors have popped up that we checked for, like an incorrect password, the `user`'s object is returned and they are authenticated.
这就是我们的用户验证逻辑: 首先根据用户输入的用户名在数据库中寻找用户;然后检查密码是否匹配,最后如果没有发生错误(比如密码错误),那么就会返回 `user` 对象并通过验证。
Many strategies are set up using different settings, but generally it is easy to set it up based on the README in that strategy's repository. A good example of this is the GitHub strategy where we don't need to worry about a username or password because the user will be sent to GitHub's auth page to authenticate. As long as they are logged in and agree then GitHub returns their profile for us to use.
很多策略的配置都不同,但是,一般来说,根据策略仓库中的 README 来进行配置就足够了。 一个很好的例子是 GitHub 策略。在该策略中,我们不需要写用户名或密码的相关验证逻辑,因为用户将被引导到 GitHub 页面进行验证。 只要用户登录并同意GitHub 就会返回用户的个人信息供我们使用。
In the next step, we will set up how to actually call the authentication strategy to validate a user based on form data!
在下一个挑战中,我们会基于表单数据调用上面写好的验证策略。
Submit your page when you think you've got it right. If you're running into errors, you can check out the project completed up to this point [here](https://gist.github.com/camperbot/53b495c02b92adeee0aa1bd3f3be8a4b).
完成上述要求后,请提交你的页面链接。 如果你遇到任何问题,可以参考[这里](https://gist.github.com/camperbot/53b495c02b92adeee0aa1bd3f3be8a4b)的答案。
# --hints--
Passport-local should be a dependency.
需要使用 passport-local 作为依赖。
```js
(getUserInput) =>
@ -57,7 +57,7 @@ Passport-local should be a dependency.
);
```
Passport-local should be correctly required and setup.
应该正确地引入和配置 passport-local
```js
(getUserInput) =>

View File

@ -1,6 +1,6 @@
---
id: 589fc831f9fc0f352b528e77
title: Authentication with Socket.IO
title: 使用 Socket.IO 进行身份验证
challengeType: 2
forumTopicId: 301548
dashedName: authentication-with-socket-io
@ -8,9 +8,9 @@ dashedName: authentication-with-socket-io
# --description--
Currently, you cannot determine who is connected to your web socket. While `req.user` contains the user object, that's only when your user interacts with the web server, and with web sockets you have no `req` (request) and therefore no user data. One way to solve the problem of knowing who is connected to your web socket is by parsing and decoding the cookie that contains the passport session then deserializing it to obtain the user object. Luckily, there is a package on NPM just for this that turns a once complex task into something simple!
目前,你还无法确定连接到服务器的用户身份。 虽然 `req.user` 包含用户信息,但这个只在用户直接与服务器交互时产生。当用户通过 web socket 与服务器连接时,由于不存在 `req` 对象,我们就无法获取用户数据。 解决这个问题的方法之一是通过读取和解析请求中包含 passport session 的 cookie然后反序列化进而获取用户信息对象。 幸运的是NPM 上有可以让这个复杂的流程简单化的库。
Add `passport.socketio`, `connect-mongo`, and `cookie-parser` as dependencies and require them as `passportSocketIo`, `MongoStore`, and `cookieParser` respectively. Also, we need to initialize a new memory store, from `express-session` which we previously required. It should look like this:
添加 `passport.socketio``connect-mongo@~3.2.0``cookie-parser` 作为依赖,把它们分别赋值给 `passportSocketIo``MongoStore``cookieParser`。 同时,我们需要从之前引入的 `express-session` 中开辟新的内存空间, 就像这样:
```js
const MongoStore = require('connect-mongo')(session);
@ -18,7 +18,7 @@ const URI = process.env.MONGO_URI;
const store = new MongoStore({ url: URI });
```
Now we just have to tell Socket.IO to use it and set the options. Be sure this is added before the existing socket code and not in the existing connection listener. For your server, it should look like this:
现在我们只需要让 Socket.IO 调用它并进行相应的配置即可。 请注意,以上这些都必须放在现有的 socket 相关代码之前,而且不能放到连接的监听回调函数里。 你的服务器代码应类似于这样:
```js
io.use(
@ -33,11 +33,11 @@ io.use(
);
```
Be sure to add the `key` and `store` to the `session` middleware mounted on the app. This is necessary to tell *SocketIO* which session to relate to.
记得要把 `key` `store` 加到 app 的 `session` 中间件。 这样,*SocketIO* 才知道该对哪个 session 执行此配置。
<hr />
Now, define the `success`, and `fail` callback functions:
接下来,我们可以定义 `success` `fail` 的回调函数:
```js
function onAuthorizeSuccess(data, accept) {
@ -53,19 +53,19 @@ function onAuthorizeFail(data, message, error, accept) {
}
```
The user object is now accessible on your socket object as `socket.request.user`. For example, now you can add the following:
现在,我们可以通过 `socket.request.user` 访问用户数据。 为此,你可以这样做:
```js
console.log('user ' + socket.request.user.name + ' connected');
```
It will log to the server console who has connected!
这样,我们可以在 console 里看到谁连接到了我们的服务器。
Submit your page when you think you've got it right. If you're running into errors, you can check out the project up to this point [here](https://gist.github.com/camperbot/1414cc9433044e306dd7fd0caa1c6254).
完成上述要求后,请提交你的页面链接。 如果你遇到了问题,可以参考[这里](https://gist.github.com/camperbot/1414cc9433044e306dd7fd0caa1c6254)的答案。
# --hints--
`passport.socketio` should be a dependency.
应添加 `passport.socketio` 作为依赖。
```js
(getUserInput) =>
@ -84,7 +84,7 @@ Submit your page when you think you've got it right. If you're running into erro
);
```
`cookie-parser` should be a dependency.
应添加 `cookie-parser` 作为依赖。
```js
(getUserInput) =>
@ -103,7 +103,7 @@ Submit your page when you think you've got it right. If you're running into erro
);
```
passportSocketIo should be properly required.
应正确引入 passportSocketIo
```js
(getUserInput) =>
@ -121,7 +121,7 @@ passportSocketIo should be properly required.
);
```
passportSocketIo should be properly setup.
应正确配置 passportSocketIo
```js
(getUserInput) =>

View File

@ -1,6 +1,6 @@
---
id: 589690e6f9fc0f352b528e6e
title: Clean Up Your Project with Modules
title: 使用模块清理项目
challengeType: 2
forumTopicId: 301549
dashedName: clean-up-your-project-with-modules
@ -8,9 +8,9 @@ dashedName: clean-up-your-project-with-modules
# --description--
Right now, everything you have is in your `server.js` file. This can lead to hard to manage code that isn't very expandable. Create 2 new files: `routes.js` and `auth.js`
目前,我们把所有的代码都放到了 `server.js` 文件里, 这会导致代码难以维护,且扩展性差。 现在让我们来创建两个新文件:`routes.js` `auth.js`
Both should start with the following code:
在每个文件的开头,我们都需要写上这段代码:
```js
module.exports = function (app, myDataBase) {
@ -18,19 +18,19 @@ module.exports = function (app, myDataBase) {
}
```
Now, in the top of your server file, require these files like so: `const routes = require('./routes.js');` Right after you establish a successful connection with the database, instantiate each of them like so: `routes(app, myDataBase)`
然后,在 server.js 文件的开头,像这样引入文件:`const routes = require('./routes.js');`。在成功连接数据库之后,像这样进行实例化:`routes(app, myDataBase)`
Finally, take all of the routes in your server and paste them into your new files, and remove them from your server file. Also take the `ensureAuthenticated` function, since it was specifically created for routing. Now, you will have to correctly add the dependencies in which are used, such as `const passport = require('passport');`, at the very top, above the export line in your `routes.js` file.
最后,把所有路由相关的代码从 server.js 移动到新文件。 不要忘了,`ensureAuthenticated` 方法的定义也要移动到新文件中,这个是我们在之前的挑战中,为在路由中判断用户是否已登录创建的函数。 然后,在 `routes.js`文件开头添加所需要的依赖,如:`const passport = require('passport');`
Keep adding them until no more errors exist, and your server file no longer has any routing (**except for the route in the catch block**)!
如果在这些步骤后没有报错,那么你已成功地从 server.js 文件中分离出了路由文件(**除了 catch block 中的路由**
Now do the same thing in your auth.js file with all of the things related to authentication such as the serialization and the setting up of the local strategy and erase them from your server file. Be sure to add the dependencies in and call `auth(app, myDataBase)` in the server in the same spot.
现在,我们来把 server.js 中与验证相关的代码分离到 auth.js 中,例如序列化,设置验证策略等。 请正确添加依赖,并在 server.js 中调用 `auth(app, myDataBase)`
Submit your page when you think you've got it right. If you're running into errors, you can check out an example of the completed project [here](https://gist.github.com/camperbot/2d06ac5c7d850d8cf073d2c2c794cc92).
完成上述要求后,请提交你的页面链接。 如果你遇到了问题,可以参考[这里](https://gist.github.com/camperbot/2d06ac5c7d850d8cf073d2c2c794cc92)的答案。
# --hints--
Modules should be present.
应该有模块。
```js
(getUserInput) =>

View File

@ -1,6 +1,6 @@
---
id: 589fc831f9fc0f352b528e75
title: Communicate by Emitting
title: 通过 Emitting 通信
challengeType: 2
forumTopicId: 301550
dashedName: communicate-by-emitting
@ -8,27 +8,27 @@ dashedName: communicate-by-emitting
# --description--
<dfn>Emit</dfn> is the most common way of communicating you will use. When you emit something from the server to 'io', you send an event's name and data to all the connected sockets. A good example of this concept would be emitting the current count of connected users each time a new user connects!
<dfn>Emit</dfn> 是你会用到的最常见的通信方式。 如果我们从服务器发送信息给 “io”就相当于把事件的名称和数据发送给了所有处于连接状态的 socket。 我们可以利用这个特性实现这样的功能:只要有新用户连接到服务器,我们就可以把目前连接的总用户数发给所有已连接的用户,这样所有用户随时都可以看到实时的在线人数。
Start by adding a variable to keep track of the users, just before where you are currently listening for connections.
首先,我们需要在监听连接的地方之前添加一个用于追踪用户数的变量:
```js
let currentUsers = 0;
```
Now, when someone connects, you should increment the count before emitting the count. So, you will want to add the incrementer within the connection listener.
然后,只要有人连接到服务器,就需要在发出用户数量之前先给这个变量加 1。 因此,需要在连接监听器中增加一个递增器。
```js
++currentUsers;
```
Finally, after incrementing the count, you should emit the event (still within the connection listener). The event should be named 'user count', and the data should just be the `currentUsers`.
最后在监听连接的地方发出emit该事件即可。 这个事件应命名为 “user count”且数据应该为 `currentUsers`
```js
io.emit('user count', currentUsers);
```
Now, you can implement a way for your client to listen for this event! Similar to listening for a connection on the server, you will use the `on` keyword.
现在,你实现了在客户端监听此事件。 类似在服务器上监听连接,你将使用 `on` 关键字。
```js
socket.on('user count', function(data) {
@ -36,13 +36,13 @@ socket.on('user count', function(data) {
});
```
Now, try loading up your app, authenticate, and you should see in your client console '1' representing the current user count! Try loading more clients up, and authenticating to see the number go up.
现在你可以尝试启动你的 app 并登录,你会看到在客户端的控制台打印出了 “1”这就表示目前连接到服务器的用户数为 1。 你可以试着通过打开多个 app 来验证数量是否会增加。
Submit your page when you think you've got it right. If you're running into errors, you can check out the project completed up to this point [here](https://gist.github.com/camperbot/28ef7f1078f56eb48c7b1aeea35ba1f5).
完成上述要求后,请提交你的页面链接。 如果你遇到了问题,可以参考[这里](https://gist.github.com/camperbot/28ef7f1078f56eb48c7b1aeea35ba1f5)的答案。
# --hints--
currentUsers should be defined.
应定义 currentUsers
```js
(getUserInput) =>
@ -60,7 +60,7 @@ currentUsers should be defined.
);
```
Server should emit the current user count at each new connection.
服务器应在有新的连接时发送当前用户数量。
```js
(getUserInput) =>
@ -78,7 +78,7 @@ Server should emit the current user count at each new connection.
);
```
Your client should be listening for 'user count' event.
客户端应监听 “user count” 事件。
```js
(getUserInput) =>

View File

@ -1,6 +1,6 @@
---
id: 5895f70df9fc0f352b528e6a
title: Create New Middleware
title: 创建新的中间件
challengeType: 2
forumTopicId: 301551
dashedName: create-new-middleware
@ -8,9 +8,9 @@ dashedName: create-new-middleware
# --description--
As is, any user can just go to `/profile` whether they have authenticated or not, by typing in the url. We want to prevent this, by checking if the user is authenticated first before rendering the profile page. This is the perfect example of when to create a middleware.
无论是否登录,任何用户都可以通过输入 url 而跳转到 `/profile`。 为了解决这个问题,我们需要在 profile 页面渲染之前进行用户验证。 这就是一个很棒的创建中间件的示例。
The challenge here is creating the middleware function `ensureAuthenticated(req, res, next)`, which will check if a user is authenticated by calling passport's `isAuthenticated` method on the `request` which, in turn, checks if `req.user` is defined. If it is, then `next()` should be called, otherwise, we can just respond to the request with a redirect to our homepage to login. An implementation of this middleware is:
这个挑战的目标是创建 `ensureAuthenticated(req, res, next)` 中间件方法,通过在 `request` 上调用 passports `isAuthenticated` 方法,可以检查 `req.user` 是否定义,从而确定用户是否通过认证。 如果用户已通过验证,就会调用 `next()`,否则我们应重定向到主页并让用户登录。 该中间件的实现如下:
```js
function ensureAuthenticated(req, res, next) {
@ -21,7 +21,7 @@ function ensureAuthenticated(req, res, next) {
};
```
Now add *ensureAuthenticated* as a middleware to the request for the profile page before the argument to the get request containing the function that renders the page.
然后,在 profile 页面请求中,添加 *ensureAuthenticated* 作为中间件,放在 get 请求(包含渲染页面的函数)的参数之前。
```js
app
@ -31,11 +31,11 @@ app
});
```
Submit your page when you think you've got it right. If you're running into errors, you can check out the project completed up to this point [here](https://gist.github.com/camperbot/ae49b8778cab87e93284a91343da0959).
完成上述要求后,请提交你的页面链接。 如果你遇到了问题,可以参考[这里](https://gist.github.com/camperbot/ae49b8778cab87e93284a91343da0959)的答案。
# --hints--
Middleware ensureAuthenticated should be implemented and on our /profile route.
应把 ensureAuthenticated 中间件添加到 /profile 路由中。
```js
(getUserInput) =>
@ -58,7 +58,7 @@ Middleware ensureAuthenticated should be implemented and on our /profile route.
);
```
A Get request to /profile should correctly redirect to / since we are not authenticated.
如果没有通过验证,对 /profile 的 GET 请求应重定向到 /。
```js
(getUserInput) =>

View File

@ -1,6 +1,6 @@
---
id: 589fc831f9fc0f352b528e76
title: Handle a Disconnect
title: 处理连接断开
challengeType: 2
forumTopicId: 301552
dashedName: handle-a-disconnect
@ -8,9 +8,9 @@ dashedName: handle-a-disconnect
# --description--
You may notice that up to now you have only been increasing the user count. Handling a user disconnecting is just as easy as handling the initial connect, except you have to listen for it on each socket instead of on the whole server.
你也许注意到,目前为止我们只处理用户数量的增加,没有处理减少。 事实上,处理用户断开连接也很简单。 区别在于,新连接的监听是发生在整个服务器上,但连接断开的监听是发生在每个 socket 上。
To do this, add another listener inside the existing `'connect'` listener that listens for `'disconnect'` on the socket with no data passed through. You can test this functionality by just logging that a user has disconnected to the console.
为此,我们需要在目前的 `'connect'` 监听里面添加另一个监听器,监听 socket 断开连接 `'disconnect'` 的事件。 通过登录已与控制台断开连接的用户,你可以测试这个功能。
```js
socket.on('disconnect', () => {
@ -18,15 +18,15 @@ socket.on('disconnect', () => {
});
```
To make sure clients continuously have the updated count of current users, you should decrease the currentUsers by 1 when the disconnect happens then emit the 'user count' event with the updated count!
为确保客户端可以看到实时的用户数量,我们应该在用户断开时让 currentUsers 减 1然后发送 “user count” 事件,并使用修改后的用户数量。
**Note:** Just like `'disconnect'`, all other events that a socket can emit to the server should be handled within the connecting listener where we have 'socket' defined.
**注意:**和 `'disconnect'` 类似,所有 socket 可以发送到服务器的事件,我们都应该在有 “socket” 定义的连接监听器里处理。
Submit your page when you think you've got it right. If you're running into errors, you can check out the project completed up to this point [here](https://gist.github.com/camperbot/ab1007b76069884fb45b215d3c4496fa).
完成上述要求后,请提交你的页面链接。 如果你遇到了问题,可以参考[这里](https://gist.github.com/camperbot/ab1007b76069884fb45b215d3c4496fa)的答案。
# --hints--
Server should handle the event disconnect from a socket.
服务器应处理断开 socket 连接的事件。
```js
(getUserInput) =>
@ -40,7 +40,7 @@ Server should handle the event disconnect from a socket.
);
```
Your client should be listening for 'user count' event.
客户端应监听 “user count” 事件。
```js
(getUserInput) =>

View File

@ -1,6 +1,6 @@
---
id: 58a25c98f9fc0f352b528e7f
title: Hashing Your Passwords
title: 哈希密码
challengeType: 2
forumTopicId: 301553
dashedName: hashing-your-passwords
@ -8,13 +8,13 @@ dashedName: hashing-your-passwords
# --description--
Going back to the information security section, you may remember that storing plaintext passwords is *never* okay. Now it is time to implement BCrypt to solve this issue.
回过头来看信息安全,你也许记得在数据库中存储明文密码是*绝对*禁止的。 现在,我们需要引入 BCrypt 来解决这个问题。
Add BCrypt as a dependency, and require it in your server. You will need to handle hashing in 2 key areas: where you handle registering/saving a new account, and when you check to see that a password is correct on login.
添加 BCrypt 作为依赖,并在服务端请求它。 你需要在两个步骤中使用哈希运算:注册和保存新账户,以及登录时检查密码是否正确。
Currently on our registration route, you insert a user's password into the database like so: `password: req.body.password`. An easy way to implement saving a hash instead is to add the following before your database logic `const hash = bcrypt.hashSync(req.body.password, 12);`, and replacing the `req.body.password` in the database saving with just `password: hash`.
目前处理注册的路由中,我们是这样把密码添加到数据库的:`password: req.body.password`。 保存哈希值的一个简单方式是在数据库逻辑中添加 `const hash = bcrypt.hashSync(req.body.password, 12);`,然后把 `req.body.password` 替换为 `password: hash`
Finally, on our authentication strategy, we check for the following in our code before completing the process: `if (password !== user.password) { return done(null, false); }`. After making the previous changes, now `user.password` is a hash. Before making a change to the existing code, notice how the statement is checking if the password is **not** equal then return non-authenticated. With this in mind, your code could look as follows to properly check the password entered against the hash:
最后,在验证逻辑中,我们已经有这样一段代码执行检查:`if (password !== user.password) { return done(null, false); }`。 现在存储的密码 `user.password` 已经是哈希值了。 在对现有代码进行修改前,注意目前的语句是如何检查如果密码**不**匹配,就返回未认证的。 牢记这一点,你的代码应该是如下,检查输入的密码是否与哈希相对照:
```js
if (!bcrypt.compareSync(password, user.password)) {
@ -22,13 +22,13 @@ if (!bcrypt.compareSync(password, user.password)) {
}
```
That is all it takes to implement one of the most important security features when you have to store passwords!
当你需要存储密码时,这样做可以有效地提升网站的安全性。
Submit your page when you think you've got it right. If you're running into errors, you can check out the project completed up to this point [here](https://gist.github.com/camperbot/dc16cca09daea4d4151a9c36a1fab564).
完成上述要求后,请提交你的页面链接。 如果你遇到了问题,可以参考[这里](https://gist.github.com/camperbot/dc16cca09daea4d4151a9c36a1fab564)的答案。
# --hints--
BCrypt should be a dependency.
应存在 BCrypt 依赖。
```js
(getUserInput) =>
@ -47,7 +47,7 @@ BCrypt should be a dependency.
);
```
BCrypt should be correctly required and implemented.
应正确地引入和调用 BCrypt。
```js
(getUserInput) =>

View File

@ -1,6 +1,6 @@
---
id: 5895f70ef9fc0f352b528e6b
title: How to Put a Profile Together
title: 如何将 Profile 放在一起
challengeType: 2
forumTopicId: 301554
dashedName: how-to-put-a-profile-together
@ -8,27 +8,27 @@ dashedName: how-to-put-a-profile-together
# --description--
Now that we can ensure the user accessing the `/profile` is authenticated, we can use the information contained in `req.user` on our page!
现在,我们能确保访问 `/profile` 页面的用户都是经过验证的,这样我们就可以在页面上使用 `req.user` 里的信息了。
Pass an object containing the property `username` and value of `req.user.username` as the second argument for the render method of the profile view. Then, go to your `profile.pug` view, and add the following line below the existing `h1` element, and at the same level of indentation:
传递一个包含属性 `username` 且属性值为 `req.user.username` 的对象,作为 profile 页面的 render 方法的第二个参数。 然后在 `profile.pug`页面,将下面的代码添加到现有的 `h1` 元素下方,处在同一级别的缩进。
```pug
h2.center#welcome Welcome, #{username}!
```
This creates an `h2` element with the class '`center`' and id '`welcome`' containing the text '`Welcome,`' followed by the username.
这样就创建了一个 `h2` 元素,具有 '`center`' class和包含文本 '`Welcome,`' 的 id '`welcome`',以及 username(用户名)。
Also, in `profile.pug`, add a link referring to the `/logout` route, which will host the logic to unauthenticate a user.
另外,在 `profile.pug` 中,添加一个指向 `/logout` 路由的链接,它将托管一个未认证用户的逻辑。
```pug
a(href='/logout') Logout
```
Submit your page when you think you've got it right. If you're running into errors, you can check out the project completed up to this point [here](https://gist.github.com/camperbot/136b3ad611cc80b41cab6f74bb460f6a).
完成上述要求后,请提交你的页面链接。 如果你遇到了问题,可以参考[这里](https://gist.github.com/camperbot/136b3ad611cc80b41cab6f74bb460f6a)的答案。
# --hints--
You should correctly add a Pug render variable to /profile.
应在 Pug render 中给 /profile 传一个变量。
```js
(getUserInput) =>

View File

@ -1,6 +1,6 @@
---
id: 5895f70df9fc0f352b528e69
title: How to Use Passport Strategies
title: 如何使用 Passport 策略
challengeType: 2
forumTopicId: 301555
dashedName: how-to-use-passport-strategies
@ -8,21 +8,21 @@ dashedName: how-to-use-passport-strategies
# --description--
In the `index.pug` file supplied, there is actually a login form. It has previously been hidden because of the inline JavaScript `if showLogin` with the form indented after it. Before `showLogin` as a variable was never defined, so it never rendered the code block containing the form. Go ahead and on the `res.render` for that page add a new variable to the object `showLogin: true`. When you refresh your page, you should then see the form! This form is set up to **POST** on `/login`, so this is where we should set up to accept the POST and authenticate the user.
在提供的 `index.pug` 文件里有一个登录表单。 因为这个表单中存在行内 JavaScript 代码 `if showLogin`,因此它是隐藏的。 因为变量 `showLogin` 未定义,所以表单不会渲染。 在该页面的 `res.render` 里,给 `showLogin: true` 对象添加一个新的变量。 当你刷新页面,就会看到表单! 表单设置为 `/login`**POST**,因此我们在这里接收 POST 请求并验证用户。
For this challenge you should add the route `/login` to accept a POST request. To authenticate on this route, you need to add a middleware to do so before then sending a response. This is done by just passing another argument with the middleware before your `function(req,res)` with your response! The middleware to use is `passport.authenticate('local')`.
在这个挑战中,你需要为 POST 请求添加路由 `/login`。 为了用这个路由进行验证,你需要在发送请求响应之前添加一个中间件。 中间件应作为参数添加到用于处理请求的函数 `function(req,res)` 之前。 对于 passport 的验证中间件,应这样调用:`passport.authenticate('local')`
`passport.authenticate` can also take some options as an argument such as: `{ failureRedirect: '/' }` which is incredibly useful, so be sure to add that in as well. The response after using the middleware (which will only be called if the authentication middleware passes) should be to redirect the user to `/profile` and that route should render the view `profile.pug`.
`passport.authenticate` 也接收选项作为参数,例如 `{ failureRedirect: '/' }` 就很有用,请记得添加到你的代码中。 如果中间件验证通过,响应应该是将用户重定向到 `/profile`,并渲染 `profile.pug`
If the authentication was successful, the user object will be saved in `req.user`.
如果验证通过,用户对象将会储存到 `req.user` 中。
At this point, if you enter a username and password in the form, it should redirect to the home page `/`, and the console of your server should display `'User {USERNAME} attempted to log in.'`, since we currently cannot login a user who isn't registered.
这时,由于我们还没有实现注册功能,如果你在表单里输入了用户名和密码,路由将会重定向到主页 `/`,在服务端将会打印 `'User {USERNAME} attempted to log in.'`
Submit your page when you think you've got it right. If you're running into errors, you can check out the project completed up to this point [here](https://gist.github.com/camperbot/7ad011ac54612ad53188b500c5e99cb9).
完成上述要求后,请提交你的页面链接。 如果你遇到了问题,可以参考[这里](https://gist.github.com/camperbot/7ad011ac54612ad53188b500c5e99cb9)的答案。
# --hints--
All steps should be correctly implemented in the server.js.
server.js 中应正确执行所有步骤。
```js
(getUserInput) =>
@ -50,7 +50,7 @@ All steps should be correctly implemented in the server.js.
);
```
A POST request to /login should correctly redirect to /.
到 /login 的 POST 请求应重定向到 /
```js
(getUserInput) =>

View File

@ -1,6 +1,6 @@
---
id: 5895f70cf9fc0f352b528e67
title: Implement the Serialization of a Passport User
title: 实现 Passport 用户的序列化
challengeType: 2
forumTopicId: 301556
dashedName: implement-the-serialization-of-a-passport-user
@ -8,11 +8,11 @@ dashedName: implement-the-serialization-of-a-passport-user
# --description--
Right now, we're not loading an actual user object since we haven't set up our database. This can be done many different ways, but for our project we will connect to the database once when we start the server and keep a persistent connection for the full life-cycle of the app. To do this, add your database's connection string (for example: `mongodb+srv://:@cluster0-jvwxi.mongodb.net/?retryWrites=true&w=majority`) to the environment variable `MONGO_URI`. This is used in the `connection.js` file.
截至目前,我们还没有配置完数据库,因此还无法加载用户数据。 实现这个的方式很多,但对于我们的项目,一旦服务器启动,那么只要有 app 实例在运行,数据库就应一直处于连接状态。 为此,你需要在环境变量 `MONGO_URI` 中添加你的数据库地址(比如:`mongodb+srv://:@cluster0-jvwxi.mongodb.net/?retryWrites=true&w=majority`)。 我们会在 `connection.js` 文件中调用它。
*You can set up a free database on [MongoDB Atlas](https://www.mongodb.com/cloud/atlas).*
*你可以在 [MongoDB Atlas](https://www.mongodb.com/cloud/atlas) 创建一个免费的数据库。*
Now we want to connect to our database then start listening for requests. The purpose of this is to not allow requests before our database is connected or if there is a database error. To accomplish this, you will want to encompass your serialization and your app routes in the following code:
现在我们想要连接到数据库,然后开始监听请求。 这样做的目的是在连接数据库之前或者出现数据库错误时,不接收任何请求。 要实现这一点,你需要在以下代码中包含序列化和应用的路由:
```js
myDB(async client => {
@ -38,13 +38,13 @@ myDB(async client => {
// app.listen out here...
```
Be sure to uncomment the `myDataBase` code in `deserializeUser`, and edit your `done(null, null)` to include the `doc`.
记得要取消 `deserializeUser``myDataBase` 的注释,并把 `doc` 添加到 `done(null, null)`
Submit your page when you think you've got it right. If you're running into errors, you can check out the project completed up to this point [here](https://gist.github.com/camperbot/175f2f585a2d8034044c7e8857d5add7).
完成上述要求后,请提交你的页面链接。 如果你遇到了问题,可以参考[这里](https://gist.github.com/camperbot/175f2f585a2d8034044c7e8857d5add7)的答案。
# --hints--
Database connection should be present.
应存在数据库连接。
```js
(getUserInput) =>
@ -62,7 +62,7 @@ Database connection should be present.
);
```
Deserialization should now be correctly using the DB and `done(null, null)` should be called with the `doc`.
序列化应正确使用数据库,应用 `doc` 调用 `done(null, null)`
```js
(getUserInput) =>

View File

@ -1,6 +1,6 @@
---
id: 589a69f5f9fc0f352b528e71
title: Implementation of Social Authentication II
title: 实现第二种社交登录
challengeType: 2
forumTopicId: 301557
dashedName: implementation-of-social-authentication-ii
@ -8,11 +8,11 @@ dashedName: implementation-of-social-authentication-ii
# --description--
The last part of setting up your GitHub authentication is to create the strategy itself. For this, you will need to add the dependency of 'passport-github' to your project and require it in your `auth.js` as `GithubStrategy` like this: `const GitHubStrategy = require('passport-github').Strategy;`. Do not forget to require and configure `dotenv` to use your environment variables.
设置 GitHub 验证的最后一步是创建策略本身。 为此,你需要在项目中添加 “passport-github” 依赖,并在 `auth.js` 中 请求它,作为 `GithubStrategy`,像这样:`const GitHubStrategy = require('passport-github').Strategy;`。 别忘了请求和配置 `dotenv`,使用你的环境变量。
To set up the GitHub strategy, you have to tell Passport to use an instantiated `GitHubStrategy`, which accepts 2 arguments: an object (containing `clientID`, `clientSecret`, and `callbackURL`) and a function to be called when a user is successfully authenticated, which will determine if the user is new and what fields to save initially in the user's database object. This is common across many strategies, but some may require more information as outlined in that specific strategy's GitHub README. For example, Google requires a *scope* as well which determines what kind of information your request is asking to be returned and asks the user to approve such access. The current strategy we are implementing has its usage outlined [here](https://github.com/jaredhanson/passport-github/), but we're going through it all right here on freeCodeCamp!
为了设置 GitHub 策略,我们需要在 Passport 中使用实例化的 `GitHubStrategy`,它可以接收两个参数:一个对象(包括 `clientID``clientSecret` `callbackURL`),以及一个回调函数。在这个回调函数中,我们要处理验证成功时,判断用户是否已经在数据库中存在的逻辑,以及在用户数据库对象中最初保存哪些字段。 这种处理方式适用于绝大部分第三方验证策略,但有些策略会需要我们提供更多的信息,详情请参考相关策略的 GitHub README。 例如Google 的验证策略会要求你提供一个 *scope*,用于标示用户成功登录后,你需要从返回的对象中获取那些信息。以及,这也需要经过用户同意,你才可以获取到。 你可以在[这里](https://github.com/jaredhanson/passport-github/)了解当前我们使用的验证策略的用法,不过我们也会在 freeCodeCamp 课程中进行详细讲解。
Here's how your new strategy should look at this point:
你的新策略应该这样去实现:
```js
passport.use(new GitHubStrategy({
@ -27,13 +27,13 @@ passport.use(new GitHubStrategy({
));
```
Your authentication won't be successful yet, and it will actually throw an error without the database logic and callback, but it should log your GitHub profile to your console if you try it!
目前,你的验证部分不会成功。由于没有数据库的逻辑和回调函数,你的代码目前还会报错。但如果你试一试,就可以在控制台里看到输出了你的 GitHub 个人信息。
Submit your page when you think you've got it right. If you're running into errors, you can check out the project completed up to this point [here](https://gist.github.com/camperbot/ff3a1166684c1b184709ac0bee30dee6).
完成上述要求后,请提交你的页面链接。 如果你遇到了问题,可以参考[这里](https://gist.github.com/camperbot/ff3a1166684c1b184709ac0bee30dee6)的答案。
# --hints--
passport-github dependency should be added.
应正确添加依赖 passport-github
```js
(getUserInput) =>
@ -52,7 +52,7 @@ passport-github dependency should be added.
);
```
passport-github should be required.
应正确请求依赖 passport-github
```js
(getUserInput) =>
@ -70,7 +70,7 @@ passport-github should be required.
);
```
GitHub strategy should be setup correctly thus far.
到目前为止Github 策略应正确设置。
```js
(getUserInput) =>

View File

@ -1,6 +1,6 @@
---
id: 589a8eb3f9fc0f352b528e72
title: Implementation of Social Authentication III
title: 实现第三种社交登录
challengeType: 2
forumTopicId: 301558
dashedName: implementation-of-social-authentication-iii
@ -8,7 +8,7 @@ dashedName: implementation-of-social-authentication-iii
# --description--
The final part of the strategy is handling the profile returned from GitHub. We need to load the user's database object if it exists, or create one if it doesn't, and populate the fields from the profile, then return the user's object. GitHub supplies us a unique *id* within each profile which we can use to search with to serialize the user with (already implemented). Below is an example implementation you can use in your project--it goes within the function that is the second argument for the new strategy, right below where `console.log(profile);` currently is:
验证策略的最后一部分是处理从 GitHub 返回的个人信息。 如果用户存在,我们就需要从数据库中读取用户数据并在 profile 页面加载;否则,我们需要把用户信息添加到数据库。 GitHub 在用户信息中为我们提供了独一无二的 *id*,我们可以通过序列化的 id 在数据库中搜索用户(已实现)。 以下是这个逻辑的实现示例,我们应该把它传到新策略的第二个参数,就是目前 `console.log(profile);` 的下方:
```js
myDataBase.findOneAndUpdate(
@ -38,15 +38,15 @@ myDataBase.findOneAndUpdate(
);
```
`findOneAndUpdate` allows you to search for an object and update it. If the object doesn't exist, it will be inserted and made available to the callback function. In this example, we always set `last_login`, increment the `login_count` by `1`, and only populate the majority of the fields when a new object (new user) is inserted. Notice the use of default values. Sometimes a profile returned won't have all the information filled out or the user will keep it private. In this case, you handle it to prevent an error.
`findOneAndUpdate` 的作用是在数据库中查询对象并更新, 如果对象不存在,将插入对象,然后我们可以在回调方法里获取到插入的新对象。 在这个例子中,我们会设置 `last_login`,而且总会为 `login_count` `1`。只有在插入一个新对象(新用户)时,我们才会初始化这些字段。 另外,还需要注意默认值的使用。 有时返回的用户信息可能不全,可能是因为用户没有填写,也可能是因为用户选择不公开一部分信息。 在这种情况下,我们需要进行相应的处理,以防我们的 app 报错。
You should be able to login to your app now--try it!
你现在应该可以登录你的应用了,试试吧。
Submit your page when you think you've got it right. If you're running into errors, you can check out the project completed up to this point [here](https://gist.github.com/camperbot/183e968f0e01d81dde015d45ba9d2745).
完成上述要求后,你可以在下方提交你的页面链接。 如果你遇到了问题,可以参考 [这里](https://gist.github.com/camperbot/183e968f0e01d81dde015d45ba9d2745) 的答案。
# --hints--
GitHub strategy setup should be complete.
GitHub 策略应配置完成。
```js
(getUserInput) =>

View File

@ -1,6 +1,6 @@
---
id: 589a69f5f9fc0f352b528e70
title: Implementation of Social Authentication
title: 实现第一种社交登录
challengeType: 2
forumTopicId: 301559
dashedName: implementation-of-social-authentication
@ -8,21 +8,21 @@ dashedName: implementation-of-social-authentication
# --description--
The basic path this kind of authentication will follow in your app is:
在应用中这种验证的基本路径是:
1. User clicks a button or link sending them to our route to authenticate using a specific strategy (e.g. GitHub).
2. Your route calls `passport.authenticate('github')` which redirects them to GitHub.
3. The page the user lands on, on GitHub, allows them to login if they aren't already. It then asks them to approve access to their profile from our app.
4. The user is then returned to our app at a specific callback url with their profile if they are approved.
5. They are now authenticated, and your app should check if it is a returning profile, or save it in your database if it is not.
1. 在用户点击按钮或者链接后,进入验证页面,通过第三方平台(如 GitHub来进行用户验证。
2. 需要在路由中调用 `passport.authenticate('github')`,跳转至 GitHub 验证页面。
3. 页面跳转到 GitHub 上,如果用户未登录 GitHub就需要在这里进行登录。 登录成功后,会出现向用户申请访问权限的确认页。
4. 如果用户同意访问,则用户会回到我们提供的回调地址,带着 GitHub 那边提供的用户信息回到我们的 app 中。
5. 验证已完成。我们的应用需要查询这个用户是否已经存在。如果是新用户,那我们需要把用户信息存储到数据库。
Strategies with OAuth require you to have at least a *Client ID* and a *Client Secret* which is a way for the service to verify who the authentication request is coming from and if it is valid. These are obtained from the site you are trying to implement authentication with, such as GitHub, and are unique to your app--**THEY ARE NOT TO BE SHARED** and should never be uploaded to a public repository or written directly in your code. A common practice is to put them in your `.env` file and reference them like so: `process.env.GITHUB_CLIENT_ID`. For this challenge we're going to use the GitHub strategy.
在 OAuth 验证策略中,我们至少需要提供 *Client ID* *Client Secret*,这样第三方平台就会获悉验证请求的来源,以及这个来源是否有效。 为此,需要去我们使用的第三方验证平台(比如 GitHub获取这两个字段的值。 注意,我们获取到的这个值是唯一的,仅对我们的当前 app 有效——**因此,千万不要分享给别人**,更不要上传到公共仓库或者直接写在代码里。 通常,我们会把它们放在 `.env` 文件里,并通过 `process.env.GITHUB_CLIENT_ID` 获取。 对于这次挑战,我们将会使用 GitHub 作为验证平台。
Obtaining your *Client ID and Secret* from GitHub is done in your account profile settings under 'developer settings', then '[OAuth applications](https://github.com/settings/developers)'. Click 'Register a new application', name your app, paste in the url to your Repl.it homepage (**Not the project code's url**), and lastly, for the callback url, paste in the same url as the homepage but with `/auth/github/callback` added on. This is where users will be redirected for us to handle after authenticating on GitHub. Save the returned information as `'GITHUB_CLIENT_ID'` and `'GITHUB_CLIENT_SECRET'` in your `.env` file.
首先,你需要进入账户设置里的 “developer settings(开发者设置)”板块,在 '[OAuth applications](https://github.com/settings/developers)' 获取 *Client ID and Secret*。 点击 “Register a new application”设置你的应用名称然后把你的 Repl.it 主页地址(**不是项目代码的地址**)粘贴到 Homepage URL。然后回调 url 需要设置成上面 Homepage URL 里你粘贴的地址,但后面要加上 `/auth/github/callback`。 这样在用户通过 Github 验证后才能跳转到我们指定的页面。 在你的 `.env` 文件里将返回的信息保存为 `'GITHUB_CLIENT_ID'` `'GITHUB_CLIENT_SECRET'`
In your `routes.js` file, add `showSocialAuth: true` to the homepage route, after `showRegistration: true`. Now, create 2 routes accepting GET requests: `/auth/github` and `/auth/github/callback`. The first should only call passport to authenticate `'github'`. The second should call passport to authenticate `'github'` with a failure redirect to `/`, and then if that is successful redirect to `/profile` (similar to our last project).
在你的 `routes.js` 文件中,添加 `showSocialAuth: true` 到主页路由,在 `showRegistration: true` 的后面。 然后,为 `/auth/github` `/auth/github/callback` 创建两个接收 GET 请求的路由。 第一个只需要通过调用 passport 来验证 `'github'`。 第二个应该调用 passport 来验证 `'github'`,但需要在失败时跳转回主页 `/`,成功时跳转到用户页面 `/profile`(跳转的逻辑与上一个项目中的逻辑一样)。
An example of how `/auth/github/callback` should look is similar to how we handled a normal login:
例如 `/auth/github/callback` 应该像我们处理在上一个项目中正常的登录一样:
```js
app.route('/login')
@ -31,11 +31,11 @@ app.route('/login')
});
```
Submit your page when you think you've got it right. If you're running into errors, you can check out the project up to this point [here](https://gist.github.com/camperbot/1f7f6f76adb178680246989612bea21e).
完成上述要求后,请提交你的页面链接。 如果你遇到了问题,可以参考[这里](https://gist.github.com/camperbot/1f7f6f76adb178680246989612bea21e)的答案。
# --hints--
Route /auth/github should be correct.
路由 /auth/github 应正确配置。
```js
(getUserInput) =>
@ -53,7 +53,7 @@ Route /auth/github should be correct.
);
```
Route /auth/github/callback should be correct.
路由 /auth/github/callback 应正确配置。
```js
(getUserInput) =>

View File

@ -1,6 +1,6 @@
---
id: 58965611f9fc0f352b528e6c
title: Logging a User Out
title: 用户退出登录
challengeType: 2
forumTopicId: 301560
dashedName: logging-a-user-out
@ -8,9 +8,9 @@ dashedName: logging-a-user-out
# --description--
Creating the logout logic is easy. The route should just unauthenticate the user and redirect to the home page instead of rendering any view.
创建退出登录的逻辑是比较简单的。 只要用户尝试退出登录,路由就应重定向到主页,而不应该显示任何其他页面。
In passport, unauthenticating a user is as easy as just calling `req.logout();` before redirecting.
passport 里,只需要在重定向前调用 `req.logout();` 即可完成用户的退出登录。
```js
app.route('/logout')
@ -20,7 +20,7 @@ app.route('/logout')
});
```
You may have noticed that we're not handling missing pages (404). The common way to handle this in Node is with the following middleware. Go ahead and add this in after all your other routes:
你可能注意到我们还没有处理 404 错误,这个错误码代表页面无法找到。 在 Node 中我们通常会用如下的中间件来处理。 请在所有路由之后添加这段代码:
```js
app.use((req, res, next) => {
@ -30,11 +30,11 @@ app.use((req, res, next) => {
});
```
Submit your page when you think you've got it right. If you're running into errors, you can check out the project completed up to this point [here](https://gist.github.com/camperbot/c3eeb8a3ebf855e021fd0c044095a23b).
完成上述要求后,请提交你的页面链接。 如果你遇到了问题,可以参考[这里](https://gist.github.com/camperbot/c3eeb8a3ebf855e021fd0c044095a23b)的答案。
# --hints--
`req.Logout` should be called in your `/logout` route.
`req.Logout` 应在 `/logout` 路由中调用。
```js
(getUserInput) =>
@ -52,7 +52,7 @@ Submit your page when you think you've got it right. If you're running into erro
);
```
Logout should redirect to the home page.
退出登录后应重定向到主页 /。
```js
(getUserInput) =>

View File

@ -1,6 +1,6 @@
---
id: 58966a17f9fc0f352b528e6d
title: Registration of New Users
title: 注册新用户
challengeType: 2
forumTopicId: 301561
dashedName: registration-of-new-users
@ -8,11 +8,11 @@ dashedName: registration-of-new-users
# --description--
Now we need to allow a new user on our site to register an account. On the `res.render` for the home page add a new variable to the object passed along--`showRegistration: true`. When you refresh your page, you should then see the registration form that was already created in your `index.pug` file! This form is set up to **POST** on `/register`, so this is where we should set up to accept the **POST** and create the user object in the database.
现在我们需要为新用户添加注册帐号的功能。 首先我们需要在主页的 `res.render` 接收的变量对象中添加 `showRegistration: true`。 此时刷新页面,你会看到页面上已经显示了我们在 `index.pug` 文件中定义的注册表单。 这个表单设置了请求路径 `/register`,并将请求方法设置成 **POST**,所以我们需要在服务器接受 **POST** 请求,且在数据库中创建用户对象。
The logic of the registration route should be as follows: Register the new user > Authenticate the new user > Redirect to /profile
用户注册的逻辑:注册新用户 > 认证新用户 > 重定向到 /profile
The logic of step 1, registering the new user, should be as follows: Query database with a findOne command > if user is returned then it exists and redirect back to home *OR* if user is undefined and no error occurs then 'insertOne' into the database with the username and password, and, as long as no errors occur, call *next* to go to step 2, authenticating the new user, which we've already written the logic for in our POST */login* route.
对于步骤一的注册新用户,详细逻辑是这样的:用 findOne 命令查询数据库 > 如果返回了用户对象,则表示用户存在,然后返回主页;*或者*如果用户未定义且没有报错,则会将包含用户名和密码的用户对象通过 “insertOne” 添加到数据库,只要没有报错则会继续*下一步*:认证新用户——我们已经在 */login* 路由的 POST 请求中写好了这部分逻辑。
```js
app.route('/register')
@ -47,13 +47,13 @@ app.route('/register')
);
```
Submit your page when you think you've got it right. If you're running into errors, you can check out the project completed up to this point [here](https://gist.github.com/camperbot/b230a5b3bbc89b1fa0ce32a2aa7b083e).
完成上述要求后,请提交你的页面链接。 如果你遇到了问题,可以参考[这里](https://gist.github.com/camperbot/b230a5b3bbc89b1fa0ce32a2aa7b083e)的答案。
**NOTE:** From this point onwards, issues can arise relating to the use of the *picture-in-picture* browser. If you are using an online IDE which offers a preview of the app within the editor, it is recommended to open this preview in a new tab.
**注意:**接下来的挑战可能会在运行 *picture-in-picture*(画中画)模式的浏览器中出现问题。 如果你使用的线上 IDE 提供在 IDE 内预览 app 的功能,请考虑打开新的标签页预览。
# --hints--
You should register route and display on home.
注册路由和显示主页。
```js
(getUserInput) =>
@ -76,7 +76,7 @@ You should register route and display on home.
);
```
Registering should work.
注册功能应可以正常运行。
```js
async (getUserInput) => {
@ -104,7 +104,7 @@ async (getUserInput) => {
};
```
Login should work.
登录功能应可以正常运行。
```js
async (getUserInput) => {
@ -153,7 +153,7 @@ async (getUserInput) => {
};
```
Logout should work.
退出登录功能应可以正常运行。
```js
(getUserInput) =>
@ -171,7 +171,7 @@ Logout should work.
);
```
Profile should no longer work after logout.
退出登录后profile 页面应无法访问。
```js
(getUserInput) =>

View File

@ -1,6 +1,6 @@
---
id: 589fc832f9fc0f352b528e79
title: Send and Display Chat Messages
title: 发送和显示聊天消息
challengeType: 2
forumTopicId: 301562
dashedName: send-and-display-chat-messages
@ -8,7 +8,7 @@ dashedName: send-and-display-chat-messages
# --description--
It's time you start allowing clients to send a chat message to the server to emit to all the clients! In your `client.js` file, you should see there is already a block of code handling when the message form is submitted.
是时候开始允许用户向服务器发送聊天消息,以向所有客户端发送消息了! 在 `client.js` 文件里,你应该已经注意到了这段提交消息表单的代码:
```js
$('form').submit(function() {
@ -16,23 +16,23 @@ $('form').submit(function() {
});
```
Within the form submit code, you should emit an event after you define `messageToSend` but before you clear the text box `#m`. The event should be named `'chat message'` and the data should just be `messageToSend`.
在表单提交代码中需要处理发送emit事件它应该发生在定义 `messageToSend` 之后,以及清除 `#m` 中的文本之前。 我们称这个事件为 `'chat message'`,需发送的数据为 `messageToSend`
```js
socket.emit('chat message', messageToSend);
```
Now, on your server, you should be listening to the socket for the event `'chat message'` with the data being named `message`. Once the event is received, it should emit the event `'chat message'` to all sockets `io.emit` with the data being an object containing `name` and `message`.
在服务端,我们需要监听包含 `message` 数据的 `'chat message'` 事件。 当事件发生,我们就通过 `io.emit` 把包含 `name``message``'chat message'` 事件发送给所有已连接的 socket。
In `client.js`, you should now listen for event `'chat message'` and, when received, append a list item to `#messages` with the name, a colon, and the message!
`client.js` 中,我们需要监听 `'chat message'` 事件。只要接收到这个事件,就把包含名字和消息的内容(注意:需要在名字后添加冒号)添加到 `#messages`
At this point, the chat should be fully functional and sending messages across all clients!
至此,我们已经完成发送信息到所有客户端的功能。
Submit your page when you think you've got it right. If you're running into errors, you can check out the project completed up to this point [here](https://gist.github.com/camperbot/d7af9864375207e254f73262976d2016).
完成上述要求后,请提交你的页面链接。 如果你遇到了问题,可以参考[这里](https://gist.github.com/camperbot/d7af9864375207e254f73262976d2016)的答案。
# --hints--
Server should listen for `'chat message'` and then emit it properly.
服务端应监听 `'chat message'`,且应在监听到后发送它。
```js
(getUserInput) =>
@ -50,7 +50,7 @@ Server should listen for `'chat message'` and then emit it properly.
);
```
Client should properly handle and display the new data from event `'chat message'`.
客户端应正确处理和展示从 `'chat message'` 事件发来的新数据。
```js
(getUserInput) =>

View File

@ -1,6 +1,6 @@
---
id: 5895f70cf9fc0f352b528e66
title: Serialization of a User Object
title: 用户对象的序列化
challengeType: 2
forumTopicId: 301563
dashedName: serialization-of-a-user-object
@ -8,11 +8,11 @@ dashedName: serialization-of-a-user-object
# --description--
Serialization and deserialization are important concepts in regards to authentication. To serialize an object means to convert its contents into a small *key* that can then be deserialized into the original object. This is what allows us to know who has communicated with the server without having to send the authentication data, like the username and password, at each request for a new page.
序列化和反序列化在身份认证中是很重要的概念。 序列化一个对象就是将其内容转换成一个体积很小的 *key*,后续可以通过它反序列化为原始对象。 这样,服务器就可以在用户未登录时识别用户,或者说给这个用户一个唯一标识,用户也不需要在每次访问不同页面时都给服务器发送用户名和密码。
To set this up properly, we need to have a serialize function and a deserialize function. In Passport, we create these with `passport.serializeUser( OURFUNCTION )` and `passport.deserializeUser( OURFUNCTION )`
我们需要用到序列化和反序列化的方法来进行配置。 passport 为我们提供了 `passport.serializeUser( OURFUNCTION )` `passport.deserializeUser( OURFUNCTION )` 两个方法。
The `serializeUser` is called with 2 arguments, the full user object and a callback used by passport. A unique key to identify that user should be returned in the callback, the easiest one to use being the user's `_id` in the object. It should be unique as it generated by MongoDB. Similarly, `deserializeUser` is called with that key and a callback function for passport as well, but, this time, we have to take that key and return the full user object to the callback. To make a query search for a Mongo `_id`, you will have to create `const ObjectID = require('mongodb').ObjectID;`, and then to use it you call `new ObjectID(THE_ID)`. Be sure to add MongoDB as a dependency. You can see this in the examples below:
`serializeUser` 方法接收两个参数,分别是表示用户的对象和一个回调函数。 其中,回调函数的返回值应为这个用户的唯一标识符:最简单的写法就是让它返回用户的 `_id`。 这个属性是 MongoDB 为用户创建的唯一字段。 类似地,`deserializeUser` 也接收两个参数,分别是在序列化时生成的标识符以及一个回调函数。在回调函数里,我们需要根据根据传入的标识符(比如 \_id返回表示用户的对象。 为了在 MongoDB 中通过 query查询语句获取 `_id` 字段,首先我们需要创建 `const ObjectID = require('mongodb').ObjectID;`;然后调用它:`new ObjectID(THE_ID)`。 当然,这一切的前提都是先引入 MongoDB 作为依赖。 你可以在下面的例子中看到:
```js
passport.serializeUser((user, done) => {
@ -26,13 +26,13 @@ passport.deserializeUser((id, done) => {
});
```
NOTE: This `deserializeUser` will throw an error until we set up the DB in the next step, so for now comment out the whole block and just call `done(null, null)` in the function `deserializeUser`.
因此,在我们在下一步中配置 DB 前,`deserializeUser` 会抛出错误。所以,现在请先注释掉上面的代码,在 `deserializeUser` 中仅调用 `done(null, null)` 即可。
Submit your page when you think you've got it right. If you're running into errors, you can check out the project completed up to this point [here](https://gist.github.com/camperbot/7068a0d09e61ec7424572b366751f048).
完成上述要求后,请提交你的页面链接。 如果你遇到了问题,可以参考 [这里](https://gist.github.com/camperbot/7068a0d09e61ec7424572b366751f048) 的答案。
# --hints--
You should serialize user function correctly.
应该正确地序列化用户函数。
```js
(getUserInput) =>
@ -55,7 +55,7 @@ You should serialize user function correctly.
);
```
You should deserialize user function correctly.
应该正确地反序列化用户函数。
```js
(getUserInput) =>
@ -78,7 +78,7 @@ You should deserialize user function correctly.
);
```
MongoDB should be a dependency.
MongoDB 应作为项目的依赖。
```js
(getUserInput) =>
@ -97,7 +97,7 @@ MongoDB should be a dependency.
);
```
Mongodb should be properly required including the ObjectId.
应该正确请求 Mongodb包括 ObjectId
```js
(getUserInput) =>

View File

@ -1,6 +1,6 @@
---
id: 5895f700f9fc0f352b528e63
title: Set up a Template Engine
title: 设置模板引擎
challengeType: 2
forumTopicId: 301564
dashedName: set-up-a-template-engine
@ -8,25 +8,31 @@ dashedName: set-up-a-template-engine
# --description--
As a reminder, this project is built upon the following starter project on [Repl.it](https://repl.it/github/freeCodeCamp/boilerplate-advancednode), or clone from [GitHub](https://github.com/freeCodeCamp/boilerplate-advancednode/).
你可以采用下面的任意一种方式完成这些挑战:
A template engine enables you to use static template files (such as those written in *Pug*) in your app. At runtime, the template engine replaces variables in a template file with actual values which can be supplied by your server. Then it transforms the template into a static HTML file that is sent to the client. This approach makes it easier to design an HTML page and allows for displaying variables on the page without needing to make an API call from the client.
- 克隆[这个 GitHub 仓库](https://github.com/freeCodeCamp/boilerplate-advancednode/),在本地完成这些挑战。
- 使用[我们在 Repl.it 上的初始化项目](https://repl.it/github/freeCodeCamp/boilerplate-advancednode)来完成这些挑战。
- 使用一个你选择的站点生成器来完成项目。 需要确定包含了我们 GitHub 仓库的所有文件。
Add `pug@~3.0.0` as a dependency in your `package.json` file.
完成本项目后,请将一个正常运行的 demo项目演示托管在可以公开访问的平台。 然后在 `Solution Link` 框中提交你的项目 URL。
Express needs to know which template engine you are using. We will use the `set` method to assign `pug` as the `view engine` property's value: `app.set('view engine', 'pug')`
你可以在应用的模版引擎中使用静态模板文件(如那些写在 *Pug* 里的)。 在运行时,模版引擎会用服务端的真实数据替换掉模版文件中的变量, 然后将模版转译成发送给客户端的 HTML 静态文件。 这样可以轻松地构造 HTML 页面,允许在页面直接显示变量内容而不需要从客户端发送 API 请求。
Your page will not load until you correctly render the index file in the `views/pug` directory.
`package.json` 文件中添加依赖 `pug@~3.0.0`
Change the argument of the `res.render()` declaration in the `/` route to be the file path to the `views/pug` directory. The path can be a relative path (relative to views), or an absolute path, and does not require a file extension.
Express 需要知道你正在使用哪个模板引擎。 我们将使用 `set` 方法来分配 `pug` 作为 `view engine` 属性的值: `app.set('view engine', 'pug')`
If all went as planned, your app home page will stop showing the message "`Pug template is not defined.`" and will now display a message indicating you've successfully rendered the Pug template!
在正确渲染 `views/pug` 目录中的索引文件之后,加载页面。
Submit your page when you think you've got it right. If you're running into errors, you can check out the project completed up to this point [here](https://gist.github.com/camperbot/3515cd676ea4dfceab4e322f59a37791).
修改 `/` 路由中 `res.render()` 声明的参数为 `views/pug` 目录的文件路径。 这个路径可以是相对路径(相对于 views也可以是绝对路径不需要文件扩展。
如果一切顺利,那么你的应用主页不会再显示信息 “`Pug template is not defined.`”,而是会显示一个信息表明你已经成功渲染 Pug 模版!
完成以上要求后,请提交你的页面链接。 如果你遇到问题,可以查看[这里](https://gist.github.com/camperbot/3515cd676ea4dfceab4e322f59a37791)的答案。
# --hints--
Pug should be a dependency.
项目中应使用 Pug 作为依赖。
```js
(getUserInput) =>
@ -45,7 +51,7 @@ Pug should be a dependency.
);
```
View engine should be Pug.
View 引擎应该是 Pug
```js
(getUserInput) =>
@ -63,7 +69,7 @@ View engine should be Pug.
);
```
Use the correct ExpressJS method to render the index page from the response.
使用正确的 ExpressJS 方法渲染来自响应的索引页。
```js
(getUserInput) =>
@ -81,7 +87,7 @@ Use the correct ExpressJS method to render the index page from the response.
);
```
Pug should be working.
Pug 应该正常运行。
```js
(getUserInput) =>

View File

@ -1,6 +1,6 @@
---
id: 5895f70cf9fc0f352b528e65
title: Set up Passport
title: 设置 Passport
challengeType: 2
forumTopicId: 301565
dashedName: set-up-passport
@ -8,15 +8,15 @@ dashedName: set-up-passport
# --description--
It's time to set up *Passport* so we can finally start allowing a user to register or login to an account! In addition to Passport, we will use Express-session to handle sessions. Using this middleware saves the session id as a cookie in the client and allows us to access the session data using that id on the server. This way we keep personal account information out of the cookie used by the client to verify to our server they are authenticated and just keep the *key* to access the data stored on the server.
现在我们来创建 *Passport*,最终我们需要用它来实现用户注册和登录。 除了 Passport我们还会用 Express-session 来处理 session会话。 在客户端,我们可以用这个中间件把 session id 储存到 cookie。同时,我们可以在服务器上通过这个 id 访问 session 数据。 通过这种方式,我们无需把用户的个人账号信息存到 cookie来完成用户的验证。只需要用这个 id 作为 *key* 来访问服务器上用户的数据即可。
To set up Passport for use in your project, you will need to add it as a dependency first in your package.json. `"passport": "^0.3.2"`
为了在你的项目中使用 Passport首先你需要在 package.json 文件中添加依赖: `"passport": "^0.3.2"`
In addition, add Express-session as a dependency now as well. Express-session has a ton of advanced features you can use but for now we're just going to use the basics! `"express-session": "^1.15.0"`
此外,还需要添加 Express-session 作为依赖。 Express-session 有许多高级特性,但我们暂时只需要了解其基础功能。 `"express-session": "^1.15.0"`
You will need to set up the session settings now and initialize Passport. Be sure to first create the variables 'session' and 'passport' to require 'express-session' and 'passport' respectively.
现在,我们需要配置 session 并初始化 Passport。 请先创建变量 “session” 和 “passport” 来分别引入 “express-session” 和 “passport”。
To set up your express app to use the session we'll define just a few basic options. Be sure to add 'SESSION_SECRET' to your .env file and give it a random value. This is used to compute the hash used to encrypt your cookie!
为了让 express 应用可以使用 session我们需要添加一些基础选项。 请在 .env 文件中添加字段 “SESSION_SECRET”并给它赋一个随机值 便于加密 cookie、计算哈希。
```js
app.use(session({
@ -27,13 +27,13 @@ app.use(session({
}));
```
As well you can go ahead and tell your express app to **use** 'passport.initialize()' and 'passport.session()'. (For example, `app.use(passport.initialize());`)
还有,我们需要让 express **使用** passport.initialize()” 和 “passport.session()”。 (例如,`app.use(passport.initialize());`)。
Submit your page when you think you've got it right. If you're running into errors, you can check out the project completed up to this point [here](https://gist.github.com/camperbot/4068a7662a2f9f5d5011074397d6788c).
完成上述要求后,请提交你的页面链接。 如果你遇到了问题,可以参考[这里](https://gist.github.com/camperbot/4068a7662a2f9f5d5011074397d6788c)的答案。
# --hints--
Passport and Express-session should be dependencies.
应添加 Passort 和 express-session 作为依赖。
```js
(getUserInput) =>
@ -57,7 +57,7 @@ Passport and Express-session should be dependencies.
);
```
Dependencies should be correctly required.
依赖应正确引入。
```js
(getUserInput) =>
@ -80,7 +80,7 @@ Dependencies should be correctly required.
);
```
Express app should use new dependencies.
Express app 可以使用新的依赖。
```js
(getUserInput) =>
@ -103,7 +103,7 @@ Express app should use new dependencies.
);
```
Session and session secret should be correctly set up.
应正确设置 session session secret
```js
(getUserInput) =>

View File

@ -1,6 +1,6 @@
---
id: 589fc830f9fc0f352b528e74
title: Set up the Environment
title: 设置环境
challengeType: 2
forumTopicId: 301566
dashedName: set-up-the-environment
@ -8,20 +8,20 @@ dashedName: set-up-the-environment
# --description--
The following challenges will make use of the `chat.pug` file. So, in your `routes.js` file, add a GET route pointing to `/chat` which makes use of `ensureAuthenticated`, and renders `chat.pug`, with `{ user: req.user }` passed as an argument to the response. Now, alter your existing `/auth/github/callback` route to set the `req.session.user_id = req.user.id`, and redirect to `/chat`.
在接下来的挑战中,我们将会用到 `chat.pug` 文件。 首先,在你的 `routes.js` 文件中为 `/chat` 添加一个处理 GET 请求的路由,并给它传入 `ensureAuthenticated`。在回调函数中,我们需要让它渲染 `chat.pug` 文件,并在响应中包含 `{ user: req.user }` 信息。 现在,请修改 `/auth/github/callback` 路由,让它可以像这样设置 user_id`req.session.user_id = req.user.id`,并在设置完成后重定向至 `/chat`
Add `http` and `socket.io` as a dependency and require/instantiate them in your server defined as follows:
我们还需要添加 `http` `socket.io` 两个依赖项,并且像这样引入:
```javascript
const http = require('http').createServer(app);
const io = require('socket.io')(http);
```
Now that the *http* server is mounted on the *express app*, you need to listen from the *http* server. Change the line with `app.listen` to `http.listen`.
现在我们的 *express 应用*已经包含了 *http* 服务,接下来我们需要监听 *http* 服务的事件。 为此,我们需要把 `app.listen` 更新为 `http.listen`
The first thing needing to be handled is listening for a new connection from the client. The <dfn>on</dfn> keyword does just that- listen for a specific event. It requires 2 arguments: a string containing the title of the event thats emitted, and a function with which the data is passed though. In the case of our connection listener, we use *socket* to define the data in the second argument. A socket is an individual client who is connected.
需要处理的第一件事是监听客户端的新连接。 <dfn>on</dfn> 关键字就是监听这个特定事件。 它接收两个参数:一个是发出的事件的标题字符串,另一个是后续用来传递数据的回调函数。 在连接监听器中,我们用 *socket* 来代表它所包含的数据。 socket 就是指已连接到服务器的客户端。
To listen for connections to your server, add the following within your database connection:
为了可以监听服务器的连接事件,我们在数据库连接的部分加入如下代码:
```javascript
io.on('connection', socket => {
@ -29,24 +29,24 @@ io.on('connection', socket => {
});
```
Now for the client to connect, you just need to add the following to your `client.js` which is loaded by the page after you've authenticated:
对于发出连接事件的客户端,只需要在认证后页面加载出的 `client.js` 中添加以下内容:
```js
/*global io*/
let socket = io();
```
The comment suppresses the error you would normally see since 'io' is not defined in the file. We've already added a reliable CDN to the Socket.IO library on the page in chat.pug.
在这个文件中,我们没有定义 “io” 变量,但第一行的注释会阻止运行时产生的报错。 不过,我们在 chat.pug 的页面上已经为你添加好了 Socket.IO 库的 CDN。
Now try loading up your app and authenticate and you should see in your server console 'A user has connected'!
现在你可以重启一下你的 app尝试一下验证用户然后你应该会看到服务器的 console 里输出了 “A user has connected”。
**Note:**`io()` works only when connecting to a socket hosted on the same url/server. For connecting to an external socket hosted elsewhere, you would use `io.connect('URL');`.
**注意:**只有在连接到处于同一个 url/server 上的 socket 时,`io()`才可以正常执行。 如果需要连接到外部的 socket就需要这样调用`io.connect('URL');`
Submit your page when you think you've got it right. If you're running into errors, you can check out the project completed up to this point [here](https://gist.github.com/camperbot/aae41cf59debc1a4755c9a00ee3859d1).
完成上述要求后,请提交你的页面链接。 如果你遇到了问题,可以参考[这里](https://gist.github.com/camperbot/aae41cf59debc1a4755c9a00ee3859d1)的答案。
# --hints--
`socket.io` should be a dependency.
应添加 `socket.io` 作为依赖。
```js
(getUserInput) =>
@ -65,7 +65,7 @@ Submit your page when you think you've got it right. If you're running into erro
);
```
You should correctly require and instantiate `http` as `http`.
应正确引入 `http`,并实例化为 `http`
```js
(getUserInput) =>
@ -83,7 +83,7 @@ You should correctly require and instantiate `http` as `http`.
);
```
You should correctly require and instantiate `socket.io` as `io`.
应正确引入 `socket.io`,并实例化为 `io`
```js
(getUserInput) =>
@ -101,7 +101,7 @@ You should correctly require and instantiate `socket.io` as `io`.
);
```
Socket.IO should be listening for connections.
Socket.IO 应监听连接。
```js
(getUserInput) =>
@ -119,7 +119,7 @@ Socket.IO should be listening for connections.
);
```
Your client should connect to your server.
客户端应连接到服务器。
```js
(getUserInput) =>

View File

@ -1,6 +1,6 @@
---
id: 5895f70bf9fc0f352b528e64
title: Use a Template Engine's Powers
title: 使用模板引擎
challengeType: 2
forumTopicId: 301567
dashedName: use-a-template-engines-powers
@ -8,23 +8,23 @@ dashedName: use-a-template-engines-powers
# --description--
One of the greatest features of using a template engine is being able to pass variables from the server to the template file before rendering it to HTML.
模版引擎最大的特点之一就是在 HTML 页面展示之前,可以从服务端传变量到模版文件。
In your Pug file, you're able to use a variable by referencing the variable name as `#{variable_name}` inline with other text on an element or by using an equal sign on the element without a space such as `p=variable_name` which assigns the variable's value to the p element's text.
在 Pug 文件中,你可以用变量名来调用变量,比如写成 `#{variable_name}` 来实现行内调用,或像 `p=variable_name` 把元素与变量直接写在一起,这表示 p 元素的内容等价于这个变量。
We strongly recommend looking at the syntax and structure of Pug [here](https://github.com/pugjs/pug) on GitHub's README. Pug is all about using whitespace and tabs to show nested elements and cutting down on the amount of code needed to make a beautiful site.
建议大家在 [Pug 的 README](https://github.com/pugjs/pug) 里看看它的语法和用法,这样你写出的代码会相对简练。 另外要注意Pug 使用缩进来表示嵌套的代码块。
Looking at our pug file 'index.pug' included in your project, we used the variables *title* and *message*.
pug 'index.pug' 文件中,我们使用了 *title* *message* 两个变量。
To pass those along from our server, you will need to add an object as a second argument to your *res.render* with the variables and their values. For example, pass this object along setting the variables for your index view: `{title: 'Hello', message: 'Please login'}`
为了从服务器传递这些信息,你需要给 *res.render* 的第二个参数传入一个对象,其中包含变量对应的值。 比如,如果你想传递对象 `{title: 'Hello', message: 'Please login'}` 到你的主页,
It should look like: `res.render(process.cwd() + '/views/pug/index', {title: 'Hello', message: 'Please login'});` Now refresh your page and you should see those values rendered in your view in the correct spot as laid out in your index.pug file!
看起来应该像这样:`res.render(process.cwd() + '/views/pug/index', {title: 'Hello', message: 'Please login'});`。现在刷新页面,你应该看到那些值就像在 index.pug 文件中一样被渲染在页面上正确的位置。
Submit your page when you think you've got it right. If you're running into errors, you can check out the project completed up to this point [here](https://gist.github.com/camperbot/4af125119ed36e6e6a8bb920db0c0871).
完成上述要求后,请提交你的页面链接。 如果你遇到了问题,可以参考 [这里](https://gist.github.com/camperbot/4af125119ed36e6e6a8bb920db0c0871) 的答案。
# --hints--
Pug should correctly render variables.
Pug 应正确地展示变量。
```js
(getUserInput) =>

View File

@ -1,6 +1,6 @@
---
id: 587d824c367417b2b2512c4c
title: Assert Deep Equality with .deepEqual and .notDeepEqual
title: Assert.deepEqual() 和 Assert.notDeepEqual() 断言深度相等
challengeType: 2
forumTopicId: 301587
dashedName: assert-deep-equality-with--deepequal-and--notdeepequal
@ -8,17 +8,17 @@ dashedName: assert-deep-equality-with--deepequal-and--notdeepequal
# --description--
As a reminder, this project is being built upon the following starter project on [Repl.it](https://repl.it/github/freeCodeCamp/boilerplate-mochachai), or cloned from [GitHub](https://github.com/freeCodeCamp/boilerplate-mochachai/).
请注意,本项目在 [这个 Repl.it 项目](https://repl.it/github/freeCodeCamp/boilerplate-mochachai) 的基础上进行开发。 你也可以从 [GitHub](https://repl.it/github/freeCodeCamp/boilerplate-mochachai) 上克隆。
`deepEqual()` asserts that two objects are deep equal.
`deepEqual()` 断言两个对象是否深度相等。
# --instructions--
Within `tests/1_unit-tests.js` under the test labelled `#7` in the `Equality` suite, change each `assert` to either `assert.deepEqual` or `assert.notDeepEqual` to make the test pass (should evaluate to `true`). Do not alter the arguments passed to the asserts.
`tests/1_unit-tests.js` 中,在标有 `#7` `Equality` 套件里,将每个 `assert` 替换成 `assert.deepEqual` `assert.notDeepEqual`,让测试通过(应该返回 `true`)。 不要改变传入断言的参数。
# --hints--
All tests should pass.
不应有未通过的测试
```js
(getUserInput) =>
@ -32,7 +32,7 @@ All tests should pass.
);
```
You should choose the correct method for the first assertion - `deepEqual` vs. `notDeepEqual`.
请为第一个断言选择正确的方法 — `deepEqual` `notDeepEqual`
```js
(getUserInput) =>
@ -50,7 +50,7 @@ You should choose the correct method for the first assertion - `deepEqual` vs. `
);
```
You should choose the correct method for the second assertion - `deepEqual` vs. `notDeepEqual`.
请为第二个断言选择正确的方法 — `deepEqual` `notDeepEqual`
```js
(getUserInput) =>

View File

@ -1,6 +1,6 @@
---
id: 587d824c367417b2b2512c4d
title: Compare the Properties of Two Elements
title: 比较两个元素的属性
challengeType: 2
forumTopicId: 301588
dashedName: compare-the-properties-of-two-elements
@ -8,15 +8,15 @@ dashedName: compare-the-properties-of-two-elements
# --description--
As a reminder, this project is being built upon the following starter project on [Repl.it](https://repl.it/github/freeCodeCamp/boilerplate-mochachai), or cloned from [GitHub](https://github.com/freeCodeCamp/boilerplate-mochachai/).
请注意,本项目在 [这个 Repl.it 项目](https://repl.it/github/freeCodeCamp/boilerplate-mochachai) 的基础上进行开发。 你也可以从 [GitHub](https://repl.it/github/freeCodeCamp/boilerplate-mochachai) 上克隆。
# --instructions--
Within `tests/1_unit-tests.js` under the test labelled `#8` in the `Comparisons` suite, change each `assert` to either `assert.isAbove` or `assert.isAtMost` to make the test pass (should evaluate to `true`). Do not alter the arguments passed to the asserts.
`tests/1_unit-tests.js` 中,在标有 `#8` `Comparisons` 套件里,将每个 `assert` 改成 `assert.isAbove` `assert.isAtMost` 方法,让测试通过(结果应该返回 `true`)。 不要改变传入断言的参数。
# --hints--
All tests should pass.
不应有未通过的测试
```js
(getUserInput) =>
@ -30,7 +30,7 @@ All tests should pass.
);
```
You should choose the correct method for the first assertion - `isAbove` vs. `isAtMost`.
请为第一个断言选择正确的方法 — `isAbove` `isAtMost`
```js
(getUserInput) =>
@ -48,7 +48,7 @@ You should choose the correct method for the first assertion - `isAbove` vs. `is
);
```
You should choose the correct method for the second assertion - `isAbove` vs. `isAtMost`.
请为第二个断言选择正确的方法 — `isAbove` `isAtMost`
```js
(getUserInput) =>
@ -62,7 +62,7 @@ You should choose the correct method for the second assertion - `isAbove` vs. `i
);
```
You should choose the correct method for the third assertion - `isAbove` vs. `isAtMost`.
请为第三个断言选择正确的方法 — `isAbove` `isAtMost`
```js
(getUserInput) =>
@ -80,7 +80,7 @@ You should choose the correct method for the third assertion - `isAbove` vs. `is
);
```
You should choose the correct method for the fourth assertion - `isAbove` vs. `isAtMost`.
请为第四个断言选择正确的方法 — `isAbove` `isAtMost`
```js
(getUserInput) =>

View File

@ -1,6 +1,6 @@
---
id: 587d824a367417b2b2512c46
title: Learn How JavaScript Assertions Work
title: 了解 JavaScript 断言的工作原理
challengeType: 2
forumTopicId: 301589
dashedName: learn-how-javascript-assertions-work
@ -8,15 +8,21 @@ dashedName: learn-how-javascript-assertions-work
# --description--
As a reminder, this project is being built upon the following starter project on [Repl.it](https://repl.it/github/freeCodeCamp/boilerplate-mochachai), or cloned from [GitHub](https://github.com/freeCodeCamp/boilerplate-mochachai/).
你可以采用下面的任意一种方式完成这些挑战:
- 克隆[这个 GitHub 仓库](https://github.com/freeCodeCamp/boilerplate-mochachai/)并在本地完成项目。
- 使用[我们在 Repl.it 上的初始化项目](https://repl.it/github/freeCodeCamp/boilerplate-mochachai)来完成这些挑战。
- 使用一个你喜欢的站点生成器来完成项目。 需要确定包含了我们 GitHub 仓库的所有文件。
完成本项目后,请将一个正常运行的 demo项目演示托管在可以公开访问的平台。 然后在 `Solution Link` 框中提交你的项目 URL。
# --instructions--
Within `tests/1_unit-tests.js` under the test labelled `#1` in the `Basic Assertions` suite, change each `assert` to either `assert.isNull` or `assert.isNotNull` to make the test pass (should evaluate to `true`). Do not alter the arguments passed to the asserts.
`tests/1_unit-tests.js` 文件下 `Basic Assertions` suite 内注释为 `#1` 的地方,将每一个 `assert` 更改为 `assert.isNull` `assert.isNotNull` 以使测试通过(应该返回 `true`)。 不要改变传入断言的参数。
# --hints--
All tests should pass.
所有测试都应该通过。
```js
(getUserInput) =>
@ -30,7 +36,7 @@ All tests should pass.
);
```
You should choose the correct method for the first assertion - `isNull` vs. `isNotNull`.
请为第一个断言选择正确的方法— `isNull` `isNotNull`
```js
(getUserInput) =>
@ -44,7 +50,7 @@ You should choose the correct method for the first assertion - `isNull` vs. `isN
);
```
You should choose the correct method for the second assertion - `isNull` vs. `isNotNull`.
请为第二个断言选择正确的方法— `isNull` `isNotNull`
```js
(getUserInput) =>

View File

@ -1,6 +1,6 @@
---
id: 587d824f367417b2b2512c5a
title: Run Functional Tests on an API Response using Chai-HTTP III - PUT method
title: 使用 Chai-HTTP III PUT 方法对 API 请求运行功能测试
challengeType: 2
forumTopicId: 301590
dashedName: run-functional-tests-on-an-api-response-using-chai-http-iii---put-method
@ -8,9 +8,9 @@ dashedName: run-functional-tests-on-an-api-response-using-chai-http-iii---put-me
# --description--
As a reminder, this project is being built upon the following starter project on [Repl.it](https://repl.it/github/freeCodeCamp/boilerplate-mochachai), or cloned from [GitHub](https://github.com/freeCodeCamp/boilerplate-mochachai/).
请注意,本项目在 [这个 Repl.it 项目](https://repl.it/github/freeCodeCamp/boilerplate-mochachai) 的基础上进行开发。你也可以从 [GitHub](https://repl.it/github/freeCodeCamp/boilerplate-mochachai) 上克隆。
In the next example we'll see how to send data in a request payload (body). We are going to test a PUT request. The `'/travellers'` endpoint accepts a JSON object taking the structure:
接下来,我们将了解如何使用请求的 payloadbody)发送数据。 我们需要测试一个 PUT 请求, `'/travellers'` 接收如下的 JSON 对象:
```json
{
@ -18,7 +18,7 @@ In the next example we'll see how to send data in a request payload (body). We a
}
```
The route responds with :
路由响应如下:
```json
{
@ -26,13 +26,13 @@ The route responds with :
}
```
See the server code for more details.
更多细节请查看服务器代码。
# --instructions--
Within `tests/2_functional-tests.js`, alter the `'send {surname: "Colombo"}'` test (`// #3`):
`tests/2_functional-tests.js` 中,修改 `'send {surname: "Colombo"}'` 测试(`// #3`
Send the following JSON response as a payload:
发送以下 JSON 响应作为有效载荷:
```json
{
@ -40,18 +40,18 @@ Send the following JSON response as a payload:
}
```
Check for the following, within the `request.end` callback:
`request.end` 返回中检查以下情况:
1. `status`
2. `type`
3. `body.name`
4. `body.surname`
Follow the assertion order above - we rely on it. Be sure to remove `assert.fail()`, once complete.
请按照以上顺序书写断言,顺序错误会影响系统判定。 完成后,请务必移除 `assert.fail()`
# --hints--
All tests should pass.
应通过所有测试。
```js
(getUserInput) =>
@ -65,7 +65,7 @@ All tests should pass.
);
```
You should test for 'res.status' to be 200.
应测试 “res.status” 是否为 200
```js
(getUserInput) =>
@ -81,7 +81,7 @@ You should test for 'res.status' to be 200.
);
```
You should test for 'res.type' to be 'application/json'.
需要测试 “res.type” 是否为 “application/json”。
```js
(getUserInput) =>
@ -97,7 +97,7 @@ You should test for 'res.type' to be 'application/json'.
);
```
You should test for 'res.body.name' to be 'Cristoforo'.
需要测试 “res.body.name” 是否为 “Cristoforo”。
```js
(getUserInput) =>
@ -113,7 +113,7 @@ You should test for 'res.body.name' to be 'Cristoforo'.
);
```
You should test for 'res.body.surname' to be 'Colombo'.
需要测试 “res.body.surname” 是否为 “Colombo”。
```js
(getUserInput) =>

View File

@ -1,6 +1,6 @@
---
id: 587d824f367417b2b2512c5b
title: Run Functional Tests on an API Response using Chai-HTTP IV - PUT method
title: 使用 Chai-HTTP IV PUT 方法对 API 响应运行功能测试
challengeType: 2
forumTopicId: 301591
dashedName: run-functional-tests-on-an-api-response-using-chai-http-iv---put-method
@ -8,15 +8,15 @@ dashedName: run-functional-tests-on-an-api-response-using-chai-http-iv---put-met
# --description--
As a reminder, this project is being built upon the following starter project on [Repl.it](https://repl.it/github/freeCodeCamp/boilerplate-mochachai), or cloned from [GitHub](https://github.com/freeCodeCamp/boilerplate-mochachai/). This exercise is similar to the preceding one. Look at it for the details.
请注意,本项目在 [这个 Repl.it 项目](https://repl.it/github/freeCodeCamp/boilerplate-mochachai) 的基础上进行开发。你也可以从 [GitHub](https://repl.it/github/freeCodeCamp/boilerplate-mochachai) 上克隆。 这个练习与上一个类似, 我们详细看看。
Now that you have seen how it is done, it is your turn to do it from scratch.
你已经看到了它是如何完成的,现在你需要从零开始搭建。
# --instructions--
Within `tests/2_functional-tests.js`, alter the `'send {surname: "da Verrazzano"}'` test (`// #4`):
`tests/2_functional-tests.js` 中,修改 `'send {surname: "da Verrazzano"}'` 测试(`// #4`)。
Send the following JSON response as a payload to the `/travellers` route:
发送以下 JSON 响应作为有效载荷到 `/travellers` 路径:
```json
{
@ -24,18 +24,18 @@ Send the following JSON response as a payload to the `/travellers` route:
}
```
Check for the following, within a `request.end` callback:
`request.end` 返回中检查以下情况:
1. `status`
2. `type`
3. `body.name`
4. `body.surname`
Follow the assertion order above - we rely on it. Be sure to remove `assert.fail()`, once complete.
请按照以上顺序书写断言,顺序错误会影响系统判定。 完成后请务必删除 `assert.fail()`
# --hints--
All tests should pass
需要通过所有测试。
```js
(getUserInput) =>
@ -49,7 +49,7 @@ All tests should pass
);
```
You should test for 'res.status' to be 200
需要测试 “res.status” 是否为 200
```js
(getUserInput) =>
@ -65,7 +65,7 @@ You should test for 'res.status' to be 200
);
```
You should test for 'res.type' to be 'application/json'
需要测试 “res.type” 是否为 “application/json”。
```js
(getUserInput) =>
@ -81,7 +81,7 @@ You should test for 'res.type' to be 'application/json'
);
```
You should test for 'res.body.name' to be 'Giovanni'
需要测试 “res.body.name” 为 “Giovanni”。
```js
(getUserInput) =>
@ -97,7 +97,7 @@ You should test for 'res.body.name' to be 'Giovanni'
);
```
You should test for 'res.body.surname' to be 'da Verrazzano'
需要测试 “res.body.surname” 是否为 “da Verrazzano”。
```js
(getUserInput) =>

View File

@ -1,6 +1,6 @@
---
id: 587d824f367417b2b2512c59
title: Run Functional Tests on API Endpoints using Chai-HTTP II
title: 使用 Chai-HTTP II 在 API 端上运行功能测试
challengeType: 2
forumTopicId: 301592
dashedName: run-functional-tests-on-api-endpoints-using-chai-http-ii
@ -8,17 +8,17 @@ dashedName: run-functional-tests-on-api-endpoints-using-chai-http-ii
# --description--
As a reminder, this project is being built upon the following starter project on [Repl.it](https://repl.it/github/freeCodeCamp/boilerplate-mochachai), or cloned from [GitHub](https://github.com/freeCodeCamp/boilerplate-mochachai/).
请注意,本项目在[这个 Repl.it 项目](https://repl.it/github/freeCodeCamp/boilerplate-mochachai)的基础上进行开发。 你也可以从 [GitHub](https://repl.it/github/freeCodeCamp/boilerplate-mochachai) 上克隆。
# --instructions--
Within `tests/2_functional-tests.js`, alter the `'Test GET /hello with your name'` test (`// #2`) to assert the `status` and the `text` response to make the test pass.
`tests/2_functional-tests.js` 中,修改 `'Test GET /hello with your name'` 测试(`// #2`),对 `status` `text` 断言。
Send your name in the query, appending `?name=<your_name>` to the route. The endpoint responds with `'hello <your_name>'`.
在查询中发送 name`?name=<your_name>` 添加到路由。 端点响应 `'hello <your_name>'`
# --hints--
All tests should pass
应通过所有测试。
```js
(getUserInput) =>
@ -32,7 +32,7 @@ All tests should pass
);
```
You should test for 'res.status' == 200
应测试 “res.status” 是否为 200
```js
(getUserInput) =>
@ -48,7 +48,7 @@ You should test for 'res.status' == 200
);
```
You should test for 'res.text' == 'hello Guest'
应测试 “res.text“ 是否为 ”hello Guest“。
```js
(getUserInput) =>

View File

@ -1,6 +1,6 @@
---
id: 587d824e367417b2b2512c58
title: Run Functional Tests on API Endpoints using Chai-HTTP
title: 使用 Chai-HTTP 在 API 端上运行功能测试
challengeType: 2
forumTopicId: 301593
dashedName: run-functional-tests-on-api-endpoints-using-chai-http
@ -8,13 +8,13 @@ dashedName: run-functional-tests-on-api-endpoints-using-chai-http
# --description--
As a reminder, this project is being built upon the following starter project on [Repl.it](https://repl.it/github/freeCodeCamp/boilerplate-mochachai), or cloned from [GitHub](https://github.com/freeCodeCamp/boilerplate-mochachai/).
请注意,本项目在[这个 Repl.it 项目](https://repl.it/github/freeCodeCamp/boilerplate-mochachai)的基础上进行开发。你也可以从 [GitHub](https://repl.it/github/freeCodeCamp/boilerplate-mochachai) 上克隆。
Mocha allows testing asyncronous operations. There is a small (BIG) difference. Can you spot it?
Mocha 允许测试异步操作。 有一个差异, 你能发现它吗?
We can test our API endpoints using a plugin, called `chai-http`. Let's see how it works. And remember, API calls are asynchronous.
我们可以使用一个叫作 `chai-http` 的插件测试 API 端点。 让我们看看它是如何工作的。 请记住API 调用是异步的。
The following is an example of a test using `chai-http` for the `'GET /hello?name=[name] => "hello [name]"'` suite. The test sends a name string in a url query string (`?name=John`) using a `GET`request to the `server`. In the `end` method's callback function, the response object (`res`) is received and contains the `status` property. The first `assert.equal` checks if the status is equal to `200`. The second `assert.equal` checks that the response string (`res.text`) is equal to `"hello John"`.
以下是使用 `chai-http` 测试 `'GET /hello?name=[name] => "hello [name]"'` 套件的例子。 测试通过 `GET` 请求在 url 查询字符串 `?name=John` 中发送一个名称字符串给 `server`。 在 `end` 方法的回调函数中,接收包含 `status` 属性的响应对象(`res`)。 第一个 `assert.equal` 检查状态是否为 `200`。 第二个 `assert.equal` 检查响应字符串 `res.text` 是否为 `"hello John"`
```js
suite('GET /hello?name=[name] => "hello [name]"', function () {
@ -34,17 +34,17 @@ suite('GET /hello?name=[name] => "hello [name]"', function () {
});
```
Notice the `done` parameter in the test's callback function. Calling it at the end without an argument is necessary to signal successful asynchronous completion.
请注意测试的回调函数中的 `done` 参数。 在没有传入参数的情况下调用它,是成功完成异步任务所必需的。
# --instructions--
Within `tests/2_functional-tests.js`, alter the `'Test GET /hello with no name'` test (`// #1`) to assert the `status` and the `text` response to make the test pass. Do not alter the arguments passed to the asserts.
`tests/2_functional-tests.js` 中,修改 `'Test GET /hello with no name'` 测试(`// #1`),对 `status` `text` 使用断言。 不要修改传给断言的参数。
There should be no name in the query; the endpoint responds with `hello Guest`.
不要在 query 中传入 name端点将会返回 `hello Guest`
# --hints--
All tests should pass
应通过所有测试。
```js
(getUserInput) =>
@ -58,7 +58,7 @@ All tests should pass
);
```
You should test for 'res.status' == 200
应测试 “res.status” 是否为 200
```js
(getUserInput) =>
@ -74,7 +74,7 @@ You should test for 'res.status' == 200
);
```
You should test for 'res.text' == 'hello Guest'
应测试 “res.text“ 是否为 ”hello Guest“。
```js
(getUserInput) =>

View File

@ -1,6 +1,6 @@
---
id: 5f8884f4c46685731aabfc41
title: Run Functional Tests Using a Headless Browser II
title: 使用 无头浏览器 II 运行功能测试
challengeType: 2
forumTopicId: 301594
dashedName: run-functional-tests-using-a-headless-browser-ii
@ -8,27 +8,27 @@ dashedName: run-functional-tests-using-a-headless-browser-ii
# --description--
As a reminder, this project is being built upon the following starter project on [Repl.it](https://repl.it/github/freeCodeCamp/boilerplate-mochachai), or cloned from [GitHub](https://github.com/freeCodeCamp/boilerplate-mochachai/).
请注意,本项目在[这个 Repl.it 项目](https://repl.it/github/freeCodeCamp/boilerplate-mochachai)的基础上进行开发。你也可以从 [GitHub](https://repl.it/github/freeCodeCamp/boilerplate-mochachai) 上克隆。
# --instructions--
Within `tests/2_functional-tests.js`, in the `'submit "surname" : "Vespucci" - write your e2e test...'` test (`// #6`), automate filling-in and submitting the form from scratch:
`tests/2_functional-tests.js` 中,`'submit "surname" : "Vespucci" - write your e2e test...'` 测试(`// #6`),自动化填写和提交表单:
1. Fill in the form with the `surname` of `Vespucci`
2. Submit it pressing `'submit'` button
1. 在表单中填写 `Vespucci``surname`
2. 点击 `'submit'` 按钮提交表单
Within the callback:
在回调中:
1. assert that status is `200`
2. assert that the text inside the element `span#name` is `'Amerigo'`
3. assert that the text inside the element `span#surname` is `'Vespucci'`
4. assert that the element(s) `span#dates` exist and their count is `1`
1. 断言状态是正常的 `200`
2. 断言元素 `span#name` 中的文本是 `'Amerigo'`
3. 断言元素 `span#surname` 元素中的文本是 `'Vespucci'`
4. 断言有 `span#dates` 元素,它们的计数是 `1`
Do not forget to to remove the `assert.fail()` call.
不要忘记删除 `assert.fail()` 调用。
# --hints--
All tests should pass.
应通过所有测试。
```js
(getUserInput) =>
@ -42,7 +42,7 @@ All tests should pass.
);
```
You should assert that the headless browser request succeeded.
应断言无头浏览器成功执行请求。
```js
(getUserInput) =>
@ -56,7 +56,7 @@ You should assert that the headless browser request succeeded.
);
```
You should assert that the text inside the element 'span#name' is 'Amerigo'.
应断言元素 “span#surname” 中的文本为 “Vespucci”。
```js
(getUserInput) =>
@ -72,7 +72,7 @@ You should assert that the text inside the element 'span#name' is 'Amerigo'.
);
```
You should assert that the text inside the element 'span#surname' is 'Vespucci'.
应断言元素 “span#surname” 中的文本为 “Vespucci”。
```js
(getUserInput) =>
@ -88,7 +88,7 @@ You should assert that the text inside the element 'span#surname' is 'Vespucci'.
);
```
You should assert that the element 'span#dates' exist and its count is 1.
应该断言元素 “span#dates” 存在,且它的值为 1
```js
(getUserInput) =>

View File

@ -1,6 +1,6 @@
---
id: 587d8250367417b2b2512c5d
title: Run Functional Tests using a Headless Browser
title: 使用无头浏览器运行功能测试
challengeType: 2
forumTopicId: 301595
dashedName: run-functional-tests-using-a-headless-browser
@ -8,9 +8,9 @@ dashedName: run-functional-tests-using-a-headless-browser
# --description--
As a reminder, this project is being built upon the following starter project on [Repl.it](https://repl.it/github/freeCodeCamp/boilerplate-mochachai), or cloned from [GitHub](https://github.com/freeCodeCamp/boilerplate-mochachai/).
请注意,本项目在[这个 Repl.it 项目](https://repl.it/github/freeCodeCamp/boilerplate-mochachai)的基础上进行开发。 你也可以从 [GitHub](https://repl.it/github/freeCodeCamp/boilerplate-mochachai) 上克隆。
In the HTML main view we provided a input form. It sends data to the `PUT /travellers` endpoint that we used above with an Ajax request. When the request successfully completes, the client code appends a `<div>` containing the info returned by the call to the DOM. Here is an example of how to interact with this form:
在 HTML 主视图中有一个输入表格。 它发送数据到 `PUT /travellers` 端点,我们在上面的 Ajax 请求中使用。 当请求成功完成时,客户端代码会给 DOM 增加一个包含调用返回信息的 `<div>`。 下面的例子展示了如何使用这个表格:
```js
test('#test - submit the input "surname" : "Polo"', function (done) {
@ -24,36 +24,36 @@ test('#test - submit the input "surname" : "Polo"', function (done) {
}
```
First, the `fill` method of the `browser` object fills the `surname` field of the form with the value `'Polo'`. Immediately after, the `pressButton` method invokes the `submit` event listener of the form. The `pressButton` method is asynchronous.
首先, `browser` 对象的 `fill` 方法在表格的 `surname` 字段中填入值 `'Polo'`。 紧接着,`pressButton` 方法调用表单的 `submit` 事件监听器。 `pressButton` 方法是异步的。
Then, once a response is received from the AJAX request, a few assertions are made confirming:
收到 AJAX 请求的响应之后,会有几项断言确认:
1. The status of the response is `200`
2. The text within the `<span id='name'></span>` element matches `'Marco'`
3. The text within the `<span id='surname'></span>` element matches `'Polo'`
4. The there is `1` `<span id='dates'></span>` element.
1. 响应状态是 `200`
2. `<span id='name'></span>` 元素的文本是 `'Marco'`
3. `<span id='surname'></span>` 元素的文本是 `'Polo'`
4. `1` `<span id='dates'></span>` 元素。
Finally, the `done` callback is invoked, which is needed due to the asynchronous test.
最后,执行 `done`,这是异步测试所必需的。
# --instructions--
Within `tests/2_functional-tests.js`, in the `'submit "surname" : "Colombo" - write your e2e test...'` test (`// #5`), automate filling-in and submitting the form:
`tests/2_functional-tests.js` 中,`'submit "surname" : "Colombo" - write your e2e test...'` 测试(`// #5`),自动化填入和提交表单:
1. Fill in the form
2. Submit it pressing `'submit'` button.
1. 填写表单
2. 点击 `'submit'` 按钮提交表单
Within the callback:
在回调中:
1. assert that status is OK `200`
2. assert that the text inside the element `span#name` is `'Cristoforo'`
3. assert that the text inside the element `span#surname` is `'Colombo'`
4. assert that the element(s) `span#dates` exist and their count is `1`
1. 断言状态是正常的 `200`
2. 断言元素 `span#name` 中的文本是 `'Cristoforo'`
3. 断言元素 `span#surname` 元素中的文本是 `'Colombo'`
4. 断言有 `span#dates` 元素,它们的计数是 `1`
Do not forget to remove the `assert.fail()` call.
不要忘记删除 `assert.fail()` 调用。
# --hints--
All tests should pass.
应通过所有测试。
```js
(getUserInput) =>
@ -67,7 +67,7 @@ All tests should pass.
);
```
You should assert that the headless browser request succeeded.
应该断言无头浏览器请求成功。
```js
(getUserInput) =>
@ -81,7 +81,7 @@ You should assert that the headless browser request succeeded.
);
```
You should assert that the text inside the element 'span#name' is 'Cristoforo'.
应该断言元素 “span#name” 中的文字为 “Cristoforo”。
```js
(getUserInput) =>
@ -97,7 +97,7 @@ You should assert that the text inside the element 'span#name' is 'Cristoforo'.
);
```
You should assert that the text inside the element 'span#surname' is 'Colombo'.
应该断言元素 “span#surname” 中的文字为 “Colombo”。
```js
(getUserInput) =>
@ -113,7 +113,7 @@ You should assert that the text inside the element 'span#surname' is 'Colombo'.
);
```
You should assert that the element 'span#dates' exist and its count is 1.
应该断言元素 “span#dates” 存在,且它的值为 1
```js
(getUserInput) =>

View File

@ -1,45 +1,45 @@
---
id: 587d824f367417b2b2512c5c
title: Simulate Actions Using a Headless Browser
title: 使用无头浏览器模拟操作
challengeType: 2
dashedName: simulate-actions-using-a-headless-browser
---
# --description--
As a reminder, this project is being built upon the following starter project on [Repl.it](https://repl.it/github/freeCodeCamp/boilerplate-mochachai), or cloned from [GitHub](https://github.com/freeCodeCamp/boilerplate-mochachai/).
请注意,本项目在[这个 Repl.it 项目](https://repl.it/github/freeCodeCamp/boilerplate-mochachai)的基础上进行开发。你也可以从 [GitHub](https://repl.it/github/freeCodeCamp/boilerplate-mochachai) 上克隆。
In the next challenges we are going to simulate the human interaction with a page using a device called 'Headless Browser'.
在接下来的挑战中,我们将使用名为 “Headless Browser无头浏览器” 的设备模拟人与页面的交互。
A headless browser is a web browser without a graphical user interface. This kind of tool is particularly useful for testing web pages, as it is able to render and understand HTML, CSS, and JavaScript the same way a browser would.
无头浏览器是没有图形用户界面的 Web 浏览器。 这种工具对于测试网页特别有用,因为它能够以与浏览器相同的方式呈现和理解 HTMLCSS JavaScript
For these challenges we are using Zombie.JS. It's a lightweight browser which is totally based on JS, without relying on additional binaries to be installed. This feature makes it usable in an environment such as Repl.it. There are many other (more powerful) options.
针对这些挑战,我们使用 Zombie.JS。 它是一个轻量级浏览器,完全基于 JS而不需要额外的二进制文件来安装。 这个功能使我们可以在 Repl.it 等环境中使用它。 还有许多其他(更强大的)选择。
Mocha allows you to prepare the ground running some code before the actual tests. This can be useful for example to create items in the database, which will be used in the successive tests.
Mocha 允许你在实际测试之前准备一些代码运行的基础。 这可能有助于例如在数据库中创建项目,用于连续测试。
With a headless browser, before the actual testing, we need to **visit** the page we are going to inspect. The `suiteSetup` 'hook' is executed only once at the suite startup. Other different hook types can be executed before each test, after each test, or at the end of a suite. See the Mocha docs for more information.
使用无头浏览器,在进行实际测试之前,我们需要**访问**我们将要检查的页面。 `suiteSetup` hook” 仅在套件启动时执行。 其他不同的钩子类型可以在每次测试之前、每次测试之后或者在套件的末尾执行。 更多信息请参阅 Mocha 文档。
# --instructions--
Within `tests/2_functional-tests.js`, immediately after the `Browser` declaration, add your project URL to the `site` property of the variable:
`tests/2_functional-tests.js`中,紧接着 `Browser` 声明之后,将你的项目 URL 添加到变量的 `site` 属性:
```js
Browser.site = 'https://sincere-cone.gomix.me'; // Your URL here
```
If you are testing on a local environment replace the line above with
如果你在本地环境中测试,则替换上面的代码为:
```js
Browser.localhost('example.com', process.env.PORT || 3000);
```
Within `tests/2_functional-tests.js`, at the root level of the `'Functional Tests with Zombie.js'` suite, instantiate a new instance of the `Browser` object with the following code:
`tests/2_functional-tests.js` 中,在 `'Functional Tests with Zombie.js'` 套件的底部,使用以下代码实例化一个新的 `Browser` 对象:
```js
const browser = new Browser();
```
Then, use the `suiteSetup` hook to direct the `browser` to the `/` route with the following code:
然后,通过以下代码,使用 `suiteSetup` 钩子把 `browser` 指向 `/` 路由:
```js
suiteSetup(function(done) {
@ -49,7 +49,7 @@ suiteSetup(function(done) {
# --hints--
All tests should pass.
应通过所有测试。
```js
(getUserInput) =>

View File

@ -1,6 +1,6 @@
---
id: 587d824b367417b2b2512c49
title: Test for Truthiness
title: 测试真实性
challengeType: 2
forumTopicId: 301596
dashedName: test-for-truthiness
@ -8,9 +8,9 @@ dashedName: test-for-truthiness
# --description--
As a reminder, this project is being built upon the following starter project on [Repl.it](https://repl.it/github/freeCodeCamp/boilerplate-mochachai), or cloned from [GitHub](https://github.com/freeCodeCamp/boilerplate-mochachai/).
请注意,本项目在[这个 Repl.it 项目](https://repl.it/github/freeCodeCamp/boilerplate-mochachai)的基础上进行开发。你也可以从 [GitHub](https://repl.it/github/freeCodeCamp/boilerplate-mochachai) 上克隆。
`isTrue()` will test for the boolean value `true` and `isNotTrue()` will pass when given anything but the boolean value of `true`.
`isTrue()` 仅当给出的值为 Boolean `true` 时可以通过测试;`isNotTrue()` 则会在给出除 `true` 以外的值时通过测试。
```js
assert.isTrue(true, 'this will pass with the boolean value true');
@ -18,15 +18,15 @@ assert.isTrue('true', 'this will NOT pass with the string value "true"');
assert.isTrue(1, 'this will NOT pass with the number value 1');
```
`isFalse()` and `isNotFalse()` also exist, and behave similarly to their true counterparts except they look for the boolean value of `false`.
`isFalse()` `isNotFalse()` 同样存在,与上面提到的两个方法类似,只不过它们针对值为 `false` 的布尔值。
# --instructions--
Within `tests/1_unit-tests.js` under the test labelled `#4` in the `Basic Assertions` suite, change each `assert` to either `assert.isTrue` or `assert.isNotTrue` to make the test pass (should evaluate to `true`). Do not alter the arguments passed to the asserts.
`tests/1_unit-tests.js` 中,`Basic Assertions` 套件中标注为 `#4` 的测试下,修改每个 `assert` `assert.isTrue` `assert.isNotTrue`,通过测试(结果应为 `true`)。 不要修改传入断言的参数。
# --hints--
All tests should pass.
应通过所有测试。
```js
(getUserInput) =>
@ -40,7 +40,7 @@ All tests should pass.
);
```
You should choose the correct method for the first assertion - `isTrue` vs. `isNotTrue`.
应该为第一个断言选择正确的方法:`isTrue` `isNotTrue`
```js
(getUserInput) =>
@ -54,7 +54,7 @@ You should choose the correct method for the first assertion - `isTrue` vs. `isN
);
```
You should choose the correct method for the second assertion - `isTrue` vs. `isNotTrue`.
应该为第二个断言选择正确的方法:`isTrue` `isNotTrue`
```js
(getUserInput) =>
@ -72,7 +72,7 @@ You should choose the correct method for the second assertion - `isTrue` vs. `is
);
```
You should choose the correct method for the third assertion - `isTrue` vs. `isNotTrue`.
应该为第三个断言选择正确的方法:`isTrue` `isNotTrue`
```js
(getUserInput) =>

View File

@ -1,6 +1,6 @@
---
id: 587d824d367417b2b2512c53
title: Test if a String Contains a Substring
title: 测试字符串是否包含子字符串
challengeType: 2
forumTopicId: 301597
dashedName: test-if-a-string-contains-a-substring
@ -8,17 +8,17 @@ dashedName: test-if-a-string-contains-a-substring
# --description--
As a reminder, this project is being built upon the following starter project on [Repl.it](https://repl.it/github/freeCodeCamp/boilerplate-mochachai), or cloned from [GitHub](https://github.com/freeCodeCamp/boilerplate-mochachai/).
请注意,本项目在[这个 Repl.it 项目](https://repl.it/github/freeCodeCamp/boilerplate-mochachai)的基础上进行开发。你也可以从 [GitHub](https://repl.it/github/freeCodeCamp/boilerplate-mochachai) 上克隆。
`include()` and `notInclude()` work for strings too! `include()` asserts that the actual string contains the expected substring.
`include()` `notInclude()` 同样可以用于字符串。 `include()` 用于断言字符串中包含某个子字符串。
# --instructions--
Within `tests/1_unit-tests.js` under the test labelled `#14` in the `Strings` suite, change each `assert` to either `assert.include` or `assert.notInclude` to make the test pass (should evaluate to `true`). Do not alter the arguments passed to the asserts.
`tests/1_unit-tests.js` 中,`Strings` 套件里标有 `#14` 的测试下,将每个 `assert` 改成 `assert.include` `assert.notInclude` 方法,通过测试(结果应该返回 `true`)。 不要修改传给断言的参数。
# --hints--
All tests should pass.
应通过所有测试。
```js
(getUserInput) =>
@ -32,7 +32,7 @@ All tests should pass.
);
```
You should choose the correct method for the first assertion - `include` vs. `notInclude`.
应该为第一个断言选择正确的方法:`include` `notInclude`
```js
(getUserInput) =>
@ -50,7 +50,7 @@ You should choose the correct method for the first assertion - `include` vs. `no
);
```
You should choose the correct method for the second assertion - `include` vs. `notInclude`.
应该为第二个断言选择正确的方法:`include` `notInclude`
```js
(getUserInput) =>

View File

@ -1,6 +1,6 @@
---
id: 587d824c367417b2b2512c4f
title: Test if a Value Falls within a Specific Range
title: 测试某个值是否在特定范围内
challengeType: 2
forumTopicId: 301598
dashedName: test-if-a-value-falls-within-a-specific-range
@ -8,23 +8,23 @@ dashedName: test-if-a-value-falls-within-a-specific-range
# --description--
As a reminder, this project is being built upon the following starter project on [Repl.it](https://repl.it/github/freeCodeCamp/boilerplate-mochachai), or cloned from [GitHub](https://github.com/freeCodeCamp/boilerplate-mochachai/).
请注意,本项目在 [这个 Repl.it 项目](https://repl.it/github/freeCodeCamp/boilerplate-mochachai) 的基础上进行开发。 你也可以从 [GitHub](https://repl.it/github/freeCodeCamp/boilerplate-mochachai) 上克隆。
```javascript
.approximately(actual, expected, delta, [message])
```
Asserts that the `actual` is equal to `expected`, to within a +/- `delta` range.
断言 `actual` 等于 `expected`,在 +/- `delta` 的范围内。
# --instructions--
Within `tests/1_unit-tests.js` under the test labelled `#10` in the `Comparisons` suite, change each `assert` to `assert.approximately` to make the test pass (should evaluate to `true`).
`tests/1_unit-tests.js` 中,在 `Comparisons` 套件里标有 `#10` 的测试中,将每个 `assert` 改成 `assert.approximately`,让测试通过(结果应该返回 `true`)。
Choose the minimum range (3rd parameter) to make the test always pass. It should be less than 1.
选择最小范围(第三个参数)来通过所有测试。 它应该小于 1
# --hints--
All tests should pass.
不应有未通过的测试
```js
(getUserInput) =>
@ -38,7 +38,7 @@ All tests should pass.
);
```
You should choose the correct range for the first assertion - `approximately(actual, expected, range)`.
应该为第一个断言选择正确的范围——`approximately(actual, expected, range)`
```js
(getUserInput) =>
@ -57,7 +57,7 @@ You should choose the correct range for the first assertion - `approximately(act
);
```
You should choose the correct range for the second assertion - `approximately(actual, expected, range)`.
应该为第二个断言选择正确的范围——`approximately(actual, expected, range)`
```js
(getUserInput) =>

View File

@ -1,6 +1,6 @@
---
id: 587d824d367417b2b2512c52
title: Test if a Value is a String
title: 测试某个值是否为字符串
challengeType: 2
forumTopicId: 301599
dashedName: test-if-a-value-is-a-string
@ -8,17 +8,17 @@ dashedName: test-if-a-value-is-a-string
# --description--
As a reminder, this project is being built upon the following starter project on [Repl.it](https://repl.it/github/freeCodeCamp/boilerplate-mochachai), or cloned from [GitHub](https://github.com/freeCodeCamp/boilerplate-mochachai/).
请注意,本项目在[这个 Repl.it 项目](https://repl.it/github/freeCodeCamp/boilerplate-mochachai)的基础上进行开发。你也可以从 [GitHub](https://repl.it/github/freeCodeCamp/boilerplate-mochachai) 上克隆。
`isString` or `isNotString` asserts that the actual value is a string.
`isString` `isNotString` 断言一个值是否为字符串。
# --instructions--
Within `tests/1_unit-tests.js` under the test labelled `#13` in the `Strings` suite, change each `assert` to either `assert.isString` or `assert.isNotString` to make the test pass (should evaluate to `true`). Do not alter the arguments passed to the asserts.
`tests/1_unit-tests.js` 中,`Strings` 套件里标有 `#13` 的测试下,将每个 `assert` 改成 `assert.isString` `assert.isNotString` 方法,通过测试(结果应该返回 `true`)。 不要修改传给断言的参数。
# --hints--
All tests should pass.
应通过所有测试。
```js
(getUserInput) =>
@ -32,7 +32,7 @@ All tests should pass.
);
```
You should choose the correct method for the first assertion - `isString` vs. `isNotString`.
应该为第一个断言选择正确的方法:`isString` `isNotString`
```js
(getUserInput) =>
@ -50,7 +50,7 @@ You should choose the correct method for the first assertion - `isString` vs. `i
);
```
You should choose the correct method for the second assertion - `isString` vs. `isNotString`.
应该为第二个断言选择正确的方法:`isString` `isNotString`
```js
(getUserInput) =>
@ -68,7 +68,7 @@ You should choose the correct method for the second assertion - `isString` vs. `
);
```
You should choose the correct method for the third assertion - `isString` vs. `isNotString`.
应该为第三个断言选择正确的方法:`isString` `isNotString`
```js
(getUserInput) =>

View File

@ -1,6 +1,6 @@
---
id: 587d824d367417b2b2512c50
title: Test if a Value is an Array
title: 测试某个值是否为数组
challengeType: 2
forumTopicId: 301600
dashedName: test-if-a-value-is-an-array
@ -8,15 +8,15 @@ dashedName: test-if-a-value-is-an-array
# --description--
As a reminder, this project is being built upon the following starter project on [Repl.it](https://repl.it/github/freeCodeCamp/boilerplate-mochachai), or cloned from [GitHub](https://github.com/freeCodeCamp/boilerplate-mochachai/).
请注意,本项目在[这个 Repl.it 项目](https://repl.it/github/freeCodeCamp/boilerplate-mochachai)的基础上进行开发。你也可以从 [GitHub](https://repl.it/github/freeCodeCamp/boilerplate-mochachai) 上克隆。
# --instructions--
Within `tests/1_unit-tests.js` under the test labelled `#11` in the `Arrays` suite, change each `assert` to either `assert.isArray` or `assert.isNotArray` to make the test pass (should evaluate to `true`). Do not alter the arguments passed to the asserts.
`tests/1_unit-tests.js` 中,`Arrays` 套件里标有 `#11` 的测试下,将每个 `assert` 改成 `assert.isArray` `assert.isNotArray` 方法,通过测试(结果应该返回 `true`)。 不要改变传入断言的参数。
# --hints--
All tests should pass.
不应有未通过的测试
```js
(getUserInput) =>
@ -30,7 +30,7 @@ All tests should pass.
);
```
You should choose the correct method for the first assertion - `isArray` vs. `isNotArray`.
请选择正确的断言——`isArray` `isNotArray`
```js
(getUserInput) =>
@ -48,7 +48,7 @@ You should choose the correct method for the first assertion - `isArray` vs. `is
);
```
You should choose the correct method for the second assertion - `isArray` vs. `isNotArray`.
请选择正确的断言——`isArray` `isNotArray`
```js
(getUserInput) =>

View File

@ -1,6 +1,6 @@
---
id: 587d824e367417b2b2512c56
title: Test if a Value is of a Specific Data Structure Type
title: 测试值是否为特定数据结构类型
challengeType: 2
forumTopicId: 301601
dashedName: test-if-a-value-is-of-a-specific-data-structure-type
@ -8,17 +8,17 @@ dashedName: test-if-a-value-is-of-a-specific-data-structure-type
# --description--
As a reminder, this project is being built upon the following starter project on [Repl.it](https://repl.it/github/freeCodeCamp/boilerplate-mochachai), or cloned from [GitHub](https://github.com/freeCodeCamp/boilerplate-mochachai/).
请注意,本项目在[这个 Repl.it 项目](https://repl.it/github/freeCodeCamp/boilerplate-mochachai)的基础上进行开发。你也可以从 [GitHub](https://repl.it/github/freeCodeCamp/boilerplate-mochachai) 上克隆。
`#typeOf` asserts that value's type is the given string, as determined by `Object.prototype.toString`.
`#typeOf` 断言一个值的类型符合给定的类型,这个类型与 `Object.prototype.toString` 一致。
# --instructions--
Within `tests/1_unit-tests.js` under the test labelled `#17` in the `Objects` suite, change each `assert` to either `assert.typeOf` or `assert.notTypeOf` to make the test pass (should evaluate to `true`). Do not alter the arguments passed to the asserts.
`tests/1_unit-tests.js` 中,`Objects` 套件里标有 `#17` 的测试下,将每个 `assert` 改成 `assert.typeOf` `assert.notTypeOf` 方法,通过测试(结果应该返回 `true`)。 不要修改传给断言的参数。
# --hints--
All tests should pass.
应通过所有测试。
```js
(getUserInput) =>
@ -32,7 +32,7 @@ All tests should pass.
);
```
You should choose the correct method for the first assertion - `typeOf` vs. `notTypeOf`.
应该为第一个断言选择正确的方法:`typeOf` `notTypeOf`
```js
(getUserInput) =>
@ -50,7 +50,7 @@ You should choose the correct method for the first assertion - `typeOf` vs. `not
);
```
You should choose the correct method for the second assertion - `typeOf` vs. `notTypeOf`.
应该为第二个断言选择正确的方法:`typeOf` `notTypeOf`
```js
(getUserInput) =>
@ -68,7 +68,7 @@ You should choose the correct method for the second assertion - `typeOf` vs. `no
);
```
You should choose the correct method for the third assertion - `typeOf` vs. `notTypeOf`.
应该为第三个断言选择正确的方法:`typeOf` `notTypeOf`
```js
(getUserInput) =>
@ -86,7 +86,7 @@ You should choose the correct method for the third assertion - `typeOf` vs. `not
);
```
You should choose the correct method for the fourth assertion - `typeOf` vs. `notTypeOf`.
应该为第四个断言选择正确的方法:`typeOf` `notTypeOf`
```js
(getUserInput) =>
@ -104,7 +104,7 @@ You should choose the correct method for the fourth assertion - `typeOf` vs. `no
);
```
You should choose the correct method for the fifth assertion - `typeOf` vs. `notTypeOf`.
应该为第五个断言选择正确的方法:`typeOf` `notTypeOf`
```js
(getUserInput) =>

View File

@ -1,6 +1,6 @@
---
id: 587d824b367417b2b2512c47
title: Test if a Variable or Function is Defined
title: 测试变量或函数是否已定义
challengeType: 2
forumTopicId: 301602
dashedName: test-if-a-variable-or-function-is-defined
@ -8,15 +8,15 @@ dashedName: test-if-a-variable-or-function-is-defined
# --description--
As a reminder, this project is being built upon the following starter project on [Repl.it](https://repl.it/github/freeCodeCamp/boilerplate-mochachai), or cloned from [GitHub](https://github.com/freeCodeCamp/boilerplate-mochachai/).
请注意,本项目在[这个 Repl.it 项目](https://repl.it/github/freeCodeCamp/boilerplate-mochachai)的基础上进行开发。你也可以从 [GitHub](https://repl.it/github/freeCodeCamp/boilerplate-mochachai) 上克隆。
# --instructions--
Within `tests/1_unit-tests.js` under the test labelled `#2` in the `Basic Assertions` suite, change each `assert` to either `assert.isDefined()` or `assert.isUndefined()` to make the test pass (should evaluate to `true`). Do not alter the arguments passed to the asserts.
`tests/1_unit-tests.js` 中,`Basic Assertions` 套件中标注为 `#2` 的测试下,修改每个 `assert` `assert.isDefined()` `assert.isUndefined()`,通过测试(结果应为 `true`)。 不要修改传给断言的参数。
# --hints--
All tests should pass.
应通过所有测试。
```js
(getUserInput) =>
@ -30,7 +30,7 @@ All tests should pass.
);
```
You should choose the correct method for the first assertion - `isDefined` vs. `isUndefined`.
应该为第一个断言选择正确的方法:`isDefined` `isUndefined`
```js
(getUserInput) =>
@ -48,7 +48,7 @@ You should choose the correct method for the first assertion - `isDefined` vs. `
);
```
You should choose the correct method for the second assertion - `isDefined` vs. `isUndefined`.
应该为第二个断言选择正确的方法:`isDefined` `isUndefined`
```js
(getUserInput) =>
@ -66,7 +66,7 @@ You should choose the correct method for the second assertion - `isDefined` vs.
);
```
You should choose the correct method for the third assertion - `isDefined` vs. `isUndefined`.
应该为第三个断言选择正确的方法:`isDefined` `isUndefined`
```js
(getUserInput) =>

View File

@ -1,6 +1,6 @@
---
id: 587d824d367417b2b2512c51
title: Test if an Array Contains an Item
title: 测试数组是否包含项目
challengeType: 2
forumTopicId: 301603
dashedName: test-if-an-array-contains-an-item
@ -8,15 +8,15 @@ dashedName: test-if-an-array-contains-an-item
# --description--
As a reminder, this project is being built upon the following starter project on [Repl.it](https://repl.it/github/freeCodeCamp/boilerplate-mochachai), or cloned from [GitHub](https://github.com/freeCodeCamp/boilerplate-mochachai/).
请注意,本项目在[这个 Repl.it 项目](https://repl.it/github/freeCodeCamp/boilerplate-mochachai)的基础上进行开发。你也可以从 [GitHub](https://repl.it/github/freeCodeCamp/boilerplate-mochachai) 上克隆。
# --instructions--
Within `tests/1_unit-tests.js` under the test labelled `#12` in the `Arrays` suite, change each `assert` to either `assert.include` or `assert.notInclude` to make the test pass (should evaluate to `true`). Do not alter the arguments passed to the asserts.
`tests/1_unit-tests.js` 中,`Arrays` 套件里标有 `#12` 的测试下,将每个 `assert` 改成 `assert.include` `assert.notInclude` 方法,通过测试(结果应该返回 `true`)。 不要修改传给断言的参数。
# --hints--
All tests should pass.
应通过所有测试。
```js
(getUserInput) =>
@ -30,7 +30,7 @@ All tests should pass.
);
```
You should choose the correct method for the first assertion - `include` vs. `notInclude`.
应该为第一个断言选择正确的方法:`include` `notInclude`
```js
(getUserInput) =>
@ -48,7 +48,7 @@ You should choose the correct method for the first assertion - `include` vs. `no
);
```
You should choose the correct method for the second assertion - `include` vs. `notInclude`.
应该为第二个断言选择正确的方法:`include` `notInclude`
```js
(getUserInput) =>

View File

@ -1,6 +1,6 @@
---
id: 587d824e367417b2b2512c55
title: Test if an Object has a Property
title: 测试对象是否具有某个属性
challengeType: 2
forumTopicId: 301604
dashedName: test-if-an-object-has-a-property
@ -8,17 +8,17 @@ dashedName: test-if-an-object-has-a-property
# --description--
As a reminder, this project is being built upon the following starter project on [Repl.it](https://repl.it/github/freeCodeCamp/boilerplate-mochachai), or cloned from [GitHub](https://github.com/freeCodeCamp/boilerplate-mochachai/).
请注意,本项目在[这个 Repl.it 项目](https://repl.it/github/freeCodeCamp/boilerplate-mochachai)的基础上进行开发。你也可以从 [GitHub](https://repl.it/github/freeCodeCamp/boilerplate-mochachai) 上克隆。
`property` asserts that the actual object has a given property.
`property` 断言一个对象含有给定属性。
# --instructions--
Within `tests/1_unit-tests.js` under the test labelled `#16` in the `Objects` suite, change each `assert` to either `assert.property` or `assert.notProperty` to make the test pass (should evaluate to `true`). Do not alter the arguments passed to the asserts.
`tests/1_unit-tests.js` 中,`Objects` 套件里标有 `#16` 的测试下,将每个 `assert` 改成 `assert.property` `assert.notProperty` 方法,通过测试(结果应该返回 `true`)。 不要修改传给断言的参数。
# --hints--
All tests should pass.
应通过所有测试。
```js
(getUserInput) =>
@ -32,7 +32,7 @@ All tests should pass.
);
```
You should choose the correct method for the first assertion - `property` vs. `notProperty`.
应该为第一个断言选择正确的方法:`property` `notProperty`
```js
(getUserInput) =>
@ -50,7 +50,7 @@ You should choose the correct method for the first assertion - `property` vs. `n
);
```
You should choose the correct method for the second assertion - `property` vs. `notProperty`.
应该为第二个断言选择正确的方法:`property` `notProperty`
```js
(getUserInput) =>
@ -68,7 +68,7 @@ You should choose the correct method for the second assertion - `property` vs. `
);
```
You should choose the correct method for the third assertion - `property` vs. `notProperty`.
应该为第三个断言选择正确的方法:`property` `notProperty`
```js
(getUserInput) =>

View File

@ -1,6 +1,6 @@
---
id: 587d824e367417b2b2512c57
title: Test if an Object is an Instance of a Constructor
title: 测试对象是否是构造函数的实例
challengeType: 2
forumTopicId: 301605
dashedName: test-if-an-object-is-an-instance-of-a-constructor
@ -8,17 +8,17 @@ dashedName: test-if-an-object-is-an-instance-of-a-constructor
# --description--
As a reminder, this project is being built upon the following starter project on [Repl.it](https://repl.it/github/freeCodeCamp/boilerplate-mochachai), or cloned from [GitHub](https://github.com/freeCodeCamp/boilerplate-mochachai/).
请注意,本项目在[这个 Repl.it 项目](https://repl.it/github/freeCodeCamp/boilerplate-mochachai)的基础上进行开发。你也可以从 [GitHub](https://repl.it/github/freeCodeCamp/boilerplate-mochachai) 上克隆。
`#instanceOf` asserts that an object is an instance of a constructor.
`#instanceOf` 断言一个对象是一个构造器的实例。
# --instructions--
Within `tests/1_unit-tests.js` under the test labelled `#18` in the `Objects` suite, change each `assert` to either `assert.instanceOf` or `assert.notInstanceOf` to make the test pass (should evaluate to `true`). Do not alter the arguments passed to the asserts.
`tests/1_unit-tests.js` 中,`Objects` 套件里标有 `#18` 的测试下,将每个 `assert` 改成 `assert.instanceOf` `assert.notInstanceOf` 方法,通过测试(结果应该返回 `true`)。 不要修改传给断言的参数。
# --hints--
All tests should pass.
应通过所有测试。
```js
(getUserInput) =>
@ -32,7 +32,7 @@ All tests should pass.
);
```
You should choose the correct method for the first assertion - `instanceOf` vs. `notInstanceOf`.
应该为第一个断言选择正确的方法:`instanceOf` `notInstanceOf`
```js
(getUserInput) =>
@ -50,7 +50,7 @@ You should choose the correct method for the first assertion - `instanceOf` vs.
);
```
You should choose the correct method for the second assertion - `instanceOf` vs. `notInstanceOf`.
应该为第二个断言选择正确的方法:`instanceOf` `notInstanceOf`
```js
(getUserInput) =>
@ -68,7 +68,7 @@ You should choose the correct method for the second assertion - `instanceOf` vs.
);
```
You should choose the correct method for the third assertion - `instanceOf` vs. `notInstanceOf`.
应该为第三个断言选择正确的方法:`instanceOf` `notInstanceOf`
```js
(getUserInput) =>
@ -86,7 +86,7 @@ You should choose the correct method for the third assertion - `instanceOf` vs.
);
```
You should choose the correct method for the fourth assertion - `instanceOf` vs. `notInstanceOf`.
应该为第四个断言选择正确的方法:`instanceOf` `notInstanceOf`
```js
(getUserInput) =>

View File

@ -1,6 +1,6 @@
---
id: 587d824c367417b2b2512c4e
title: Test if One Value is Below or At Least as Large as Another
title: 测试一个值是否小于或等于另一个值
challengeType: 2
forumTopicId: 301606
dashedName: test-if-one-value-is-below-or-at-least-as-large-as-another
@ -8,15 +8,15 @@ dashedName: test-if-one-value-is-below-or-at-least-as-large-as-another
# --description--
As a reminder, this project is being built upon the following starter project on [Repl.it](https://repl.it/github/freeCodeCamp/boilerplate-mochachai), or cloned from [GitHub](https://github.com/freeCodeCamp/boilerplate-mochachai/).
请注意,本项目在[这个 Repl.it 项目](https://repl.it/github/freeCodeCamp/boilerplate-mochachai)的基础上进行开发。你也可以从 [GitHub](https://repl.it/github/freeCodeCamp/boilerplate-mochachai) 上克隆。
# --instructions--
Within `tests/1_unit-tests.js` under the test labelled `#9` in the `Comparisons` suite, change each `assert` to either `assert.isBelow` or `assert.isAtLeast` to make the test pass (should evaluate to `true`). Do not alter the arguments passed to the asserts.
`tests/1_unit-tests.js` 中,在 `Comparisons` 套件里标有 `#9` 的测试中,将每个 `assert` 改成 `assert.isBelow` `assert.isAtLeast` 方法,让测试通过(结果应该返回 `true`)。 不要修改传给断言的参数。
# --hints--
All tests should pass.
应通过所有测试。
```js
(getUserInput) =>
@ -30,7 +30,7 @@ All tests should pass.
);
```
You should choose the correct method for the first assertion - `isBelow` vs. `isAtLeast`.
应该为第一个断言选择正确的方法:`isBelow` `isAtLeast`
```js
(getUserInput) =>
@ -48,7 +48,7 @@ You should choose the correct method for the first assertion - `isBelow` vs. `is
);
```
You should choose the correct method for the second assertion - `isBelow` vs. `isAtLeast`.
应该为第二个断言选择正确的方法:`isBelow` `isAtLeast`
```js
(getUserInput) =>
@ -66,7 +66,7 @@ You should choose the correct method for the second assertion - `isBelow` vs. `i
);
```
You should choose the correct method for the third assertion - `isBelow` vs. `isAtLeast`.
应该为第三个断言选择正确的方法:`isBelow` `isAtLeast`
```js
(getUserInput) =>
@ -80,7 +80,7 @@ You should choose the correct method for the third assertion - `isBelow` vs. `is
);
```
You should choose the correct method for the fourth assertion - `isBelow` vs. `isAtLeast`.
应该为第四个断言选择正确的方法:`isBelow` `isAtLeast`
```js
(getUserInput) =>

View File

@ -1,6 +1,6 @@
---
id: 587d824b367417b2b2512c48
title: Use Assert.isOK and Assert.isNotOK
title: 使用 Assert.isOk() 和 Assert.isNotOK()
challengeType: 2
forumTopicId: 301607
dashedName: use-assert-isok-and-assert-isnotok
@ -8,19 +8,19 @@ dashedName: use-assert-isok-and-assert-isnotok
# --description--
As a reminder, this project is being built upon the following starter project on [Repl.it](https://repl.it/github/freeCodeCamp/boilerplate-mochachai), or cloned from [GitHub](https://github.com/freeCodeCamp/boilerplate-mochachai/).
请注意,本项目在[这个 Repl.it 项目](https://repl.it/github/freeCodeCamp/boilerplate-mochachai)的基础上进行开发。你也可以从 [GitHub](https://repl.it/github/freeCodeCamp/boilerplate-mochachai) 上克隆。
`isOk()` will test for a truthy value, and `isNotOk()` will test for a falsy value.
`isOk()` 用来测试值是否为真值,`isNotOk()` 用来测试值是否为假值。
To learn more about truthy and falsy values, try our [Falsy Bouncer](https://www.freecodecamp.org/learn/javascript-algorithms-and-data-structures/basic-algorithm-scripting/falsy-bouncer) challenge.
可以在[过滤数组中的假值](https://www.freecodecamp.org/learn/javascript-algorithms-and-data-structures/basic-algorithm-scripting/falsy-bouncer)这个挑战中了解更多关于真值和假值的信息。
# --instructions--
Within `tests/1_unit-tests.js` under the test labelled `#3` in the `Basic Assertions` suite, change each `assert` to either `assert.isOk()` or `assert.isNotOk()` to make the test pass (should evaluate to `true`). Do not alter the arguments passed to the asserts.
`tests/1_unit-tests.js` 中,`Basic Assertions` 套件中标注为 `#3` 的测试下,修改每个 `assert` `assert.isOk()` `assert.isNotOk()`,通过测试(结果应为 `true`)。 不要修改传入断言的参数。
# --hints--
All tests should pass.
应通过所有测试。
```js
(getUserInput) =>
@ -34,7 +34,7 @@ All tests should pass.
);
```
You should choose the correct method for the first assertion - `isOk` vs. `isNotOk`.
应该第一个断言选择正确的方法:`isOk` `isNotOk`
```js
(getUserInput) =>
@ -48,7 +48,7 @@ You should choose the correct method for the first assertion - `isOk` vs. `isNot
);
```
You should choose the correct method for the second assertion - `isOk` vs. `isNotOk`.
应该第二个断言选择正确的方法:`isOk` `isNotOk`
```js
(getUserInput) =>
@ -62,7 +62,7 @@ You should choose the correct method for the second assertion - `isOk` vs. `isNo
);
```
You should choose the correct method for the third assertion - `isOk` vs. `isNotOk`.
应该第三个断言选择正确的方法:`isOk` `isNotOk`
```js
(getUserInput) =>

View File

@ -1,6 +1,6 @@
---
id: 587d824d367417b2b2512c54
title: Use Regular Expressions to Test a String
title: 使用正则表达式测试字符串
challengeType: 2
forumTopicId: 301608
dashedName: use-regular-expressions-to-test-a-string
@ -8,17 +8,17 @@ dashedName: use-regular-expressions-to-test-a-string
# --description--
As a reminder, this project is being built upon the following starter project on [Repl.it](https://repl.it/github/freeCodeCamp/boilerplate-mochachai), or cloned from [GitHub](https://github.com/freeCodeCamp/boilerplate-mochachai/).
请注意,本项目在[这个 Repl.it 项目](https://repl.it/github/freeCodeCamp/boilerplate-mochachai)的基础上进行开发。你也可以从 [GitHub](https://repl.it/github/freeCodeCamp/boilerplate-mochachai) 上克隆。
`match()` asserts that the actual value matches the second argument regular expression.
`match()` 断言一个值匹配一个正则表达式(第二个参数)。
# --instructions--
Within `tests/1_unit-tests.js` under the test labelled `#15` in the `Strings` suite, change each `assert` to either `assert.match` or `assert.notMatch` to make the test pass (should evaluate to `true`). Do not alter the arguments passed to the asserts.
`tests/1_unit-tests.js` 中,`Strings` 套件里标有 `#15` 的测试下,将每个 `assert` 改成 `assert.match` `assert.notMatch` 方法,通过测试(结果应该返回 `true`)。 不要修改传给断言的参数。
# --hints--
All tests should pass.
应通过所有测试。
```js
(getUserInput) =>
@ -32,7 +32,7 @@ All tests should pass.
);
```
You should choose the correct method for the first assertion - `match` vs. `notMatch`.
应该为第一个断言选择正确的方法:`match` `notMatch`
```js
(getUserInput) =>
@ -50,7 +50,7 @@ You should choose the correct method for the first assertion - `match` vs. `notM
);
```
You should choose the correct method for the second assertion - `match` vs. `notMatch`.
应该为第二个断言选择正确的方法:`match` `notMatch`
```js
(getUserInput) =>

View File

@ -1,6 +1,6 @@
---
id: 587d824b367417b2b2512c4a
title: Use the Double Equals to Assert Equality
title: 用两个等号断言相等
challengeType: 2
forumTopicId: 301609
dashedName: use-the-double-equals-to-assert-equality
@ -8,17 +8,17 @@ dashedName: use-the-double-equals-to-assert-equality
# --description--
As a reminder, this project is being built upon the following starter project on [Repl.it](https://repl.it/github/freeCodeCamp/boilerplate-mochachai), or cloned from [GitHub](https://github.com/freeCodeCamp/boilerplate-mochachai/).
请注意,本项目在[这个 Repl.it 项目](https://repl.it/github/freeCodeCamp/boilerplate-mochachai)的基础上进行开发。你也可以从 [GitHub](https://repl.it/github/freeCodeCamp/boilerplate-mochachai) 上克隆。
`equal()` compares objects using `==`.
`equal()` 使用 `==` 比较对象。
# --instructions--
Within `tests/1_unit-tests.js` under the test labelled `#5` in the `Equality` suite, change each `assert` to either `assert.equal` or `assert.notEqual` to make the test pass (should evaluate to `true`). Do not alter the arguments passed to the asserts.
`tests/1_unit-tests.js` 中,在 `Equality` 套件里标有 `#5` 的测试里,将每个 `assert` 改为 `assert.equal` `assert.notEqual`,通过测试(应该返回 `true`)。 不要修改传给断言的参数。
# --hints--
All tests should pass.
应通过所有测试。
```js
(getUserInput) =>
@ -32,7 +32,7 @@ All tests should pass.
);
```
You should choose the correct method for the first assertion - `equal` vs. `notEqual`.
应该为第一个断言选择正确的方法:`equal` `notEqual`
```js
(getUserInput) =>
@ -50,7 +50,7 @@ You should choose the correct method for the first assertion - `equal` vs. `notE
);
```
You should choose the correct method for the second assertion - `equal` vs. `notEqual`.
应该为第二个断言选择正确的方法:`equal` `notEqual`
```js
(getUserInput) =>
@ -68,7 +68,7 @@ You should choose the correct method for the second assertion - `equal` vs. `not
);
```
You should choose the correct method for the third assertion - `equal` vs. `notEqual`.
应该为第三个断言选择正确的方法:`equal` `notEqual`
```js
(getUserInput) =>
@ -86,7 +86,7 @@ You should choose the correct method for the third assertion - `equal` vs. `notE
);
```
You should choose the correct method for the fourth assertion - `equal` vs. `notEqual`.
应该为第四个断言选择正确的方法:`equal` `notEqual`
```js
(getUserInput) =>

View File

@ -1,6 +1,6 @@
---
id: 587d824b367417b2b2512c4b
title: Use the Triple Equals to Assert Strict Equality
title: 用三个等号断言严格相等
challengeType: 2
forumTopicId: 301610
dashedName: use-the-triple-equals-to-assert-strict-equality
@ -8,17 +8,17 @@ dashedName: use-the-triple-equals-to-assert-strict-equality
# --description--
As a reminder, this project is being built upon the following starter project on [Repl.it](https://repl.it/github/freeCodeCamp/boilerplate-mochachai), or cloned from [GitHub](https://github.com/freeCodeCamp/boilerplate-mochachai/).
请注意,本项目在[这个 Repl.it 项目](https://repl.it/github/freeCodeCamp/boilerplate-mochachai)的基础上进行开发。你也可以从 [GitHub](https://repl.it/github/freeCodeCamp/boilerplate-mochachai) 上克隆。
`strictEqual()` compares objects using `===`.
`strictEqual()` 使用 `===` 比较对象。
# --instructions--
Within `tests/1_unit-tests.js` under the test labelled `#6` in the `Equality` suite, change each `assert` to either `assert.strictEqual` or `assert.notStrictEqual` to make the test pass (should evaluate to `true`). Do not alter the arguments passed to the asserts.
`tests/1_unit-tests.js` 中,在 `Equality` 套件里标有 `#6` 的测试下,将每个 `assert` 改为 `assert.strictEqual` `assert.notStrictEqual`,让测试通过(应该返回 `true`)。 不要修改传给断言的参数。
# --hints--
All tests should pass.
应通过所有测试。
```js
(getUserInput) =>
@ -32,7 +32,7 @@ All tests should pass.
);
```
You should choose the correct method for the first assertion - `strictEqual` vs. `notStrictEqual`.
应该为第一个断言选择正确的方法:`strictEqual` `notStrictEqual`
```js
(getUserInput) =>
@ -50,7 +50,7 @@ You should choose the correct method for the first assertion - `strictEqual` vs.
);
```
You should choose the correct method for the second assertion - `strictEqual` vs. `notStrictEqual`.
应该为第二个断言选择正确的方法:`strictEqual` `notStrictEqual`
```js
(getUserInput) =>
@ -64,7 +64,7 @@ You should choose the correct method for the second assertion - `strictEqual` vs
);
```
You should choose the correct method for the third assertion - `strictEqual` vs. `notStrictEqual`.
应该为第三个断言选择正确的方法:`strictEqual` `notStrictEqual`
```js
(getUserInput) =>
@ -82,7 +82,7 @@ You should choose the correct method for the third assertion - `strictEqual` vs.
);
```
You should choose the correct method for the fourth assertion - `strictEqual` vs. `notStrictEqual`.
应该为第四个断言选择正确的方法:`strictEqual` `notStrictEqual`
```js
(getUserInput) =>

View File

@ -1,68 +1,68 @@
---
id: 5e601c0d5ac9d0ecd8b94afe
title: American British Translator
title: 美式英语英式英语转换器
challengeType: 4
dashedName: american-british-translator
---
# --description--
Build a full stack JavaScript app that is functionally similar to this: <https://american-british-translator.freecodecamp.rocks/>. Working on this project will involve you writing your code using one of the following methods:
构建一个 JavaScript 的全栈应用,在功能上与这个应用相似:<https://american-british-translator.freecodecamp.rocks/>。 可以采用下面的任意一种方式完成这个挑战:
- Clone [this GitHub repo](https://github.com/freeCodeCamp/boilerplate-project-american-british-english-translator/) and complete your project locally.
- Use [our repl.it starter project](https://repl.it/github/freeCodeCamp/boilerplate-project-american-british-english-translator) to complete your project.
- Use a site builder of your choice to complete the project. Be sure to incorporate all the files from our GitHub repo.
- 克隆 [这个 GitHub 仓库](https://github.com/freeCodeCamp/boilerplate-project-american-british-english-translator/) 并在本地完成项目。
- 使用 [repl.it 上的初始化项目](https://repl.it/github/freeCodeCamp/boilerplate-project-american-british-english-translator) 来完成项目。
- 使用您选择的站点生成器来完成项目。 并确保包含了我们 GitHub 仓库的所有文件。
When you are done, make sure a working demo of your project is hosted somewhere public. Then submit the URL to it in the `Solution Link` field. Optionally, also submit a link to your project's source code in the `GitHub Link` field.
当完成本项目,请确认有一个可以公开访问的正常运行 demo 。 然后将 URL 提交到 `Solution Link` 中。 此外,还可以将项目的源码提交到 `GitHub Link` 中。
# --instructions--
- All logic can go into `/components/translator.js`
- Complete the `/api/translate` route in `/routes/api.js`
- Create all of the unit/functional tests in `tests/1_unit-tests.js` and `tests/2_functional-tests.js`
- See the JavaScript files in `/components` for the different spelling and terms your application should translate
- To run the tests on Repl.it, set `NODE_ENV` to `test` without quotes in the `.env` file
- To run the tests in the console, use the command `npm run test`. To open the Repl.it console, press Ctrl+Shift+P (Cmd if on a Mac) and type "open shell"
- 所有逻辑都可以进入 `/components/translator.js`
- `/routes/api.js` 中完成 `/api/translate` 路由
- `tests/1_unit-tests.js` `tests/2_functional-tests.js` 中创建所有 unit/functional 测试
- 查看 `/components` 中的 JavaScript 文件以获取应用程序应该翻译的条款以及不同的拼写
- `.env` 文件中将 `NODE_ENV` 设置为 `test`(没有引号),运行 Repl.it 上的测试。
- 使用 `npm run test` 命令,在 console 运行测试。 按 Ctrl+Shift+P (在 Mac 上是 Cmd+Shift+P) 并输入"open shell",打开 Repl.it 控制台。
Write the following tests in `tests/1_unit-tests.js`:
`tests/1_unit-tests.js` 中写下以下测试:
- Translate `Mangoes are my favorite fruit.` to British English
- Translate `I ate yogurt for breakfast.` to British English
- Translate `We had a party at my friend's condo.` to British English
- Translate `Can you toss this in the trashcan for me?` to British English
- Translate `The parking lot was full.` to British English
- Translate `Like a high tech Rube Goldberg machine.` to British English
- Translate `To play hooky means to skip class or work.` to British English
- Translate `No Mr. Bond, I expect you to die.` to British English
- Translate `Dr. Grosh will see you now.` to British English
- Translate `Lunch is at 12:15 today.` to British English
- Translate `We watched the footie match for a while.` to American English
- Translate `Paracetamol takes up to an hour to work.` to American English
- Translate `First, caramelise the onions.` to American English
- Translate `I spent the bank holiday at the funfair.` to American English
- Translate `I had a bicky then went to the chippy.` to American English
- Translate `I've just got bits and bobs in my bum bag.` to American English
- Translate `The car boot sale at Boxted Airfield was called off.` to American English
- Translate `Have you met Mrs Kalyani?` to American English
- Translate `Prof Joyner of King's College, London.` to American English
- Translate `Tea time is usually around 4 or 4.30.` to American English
- Highlight translation in `Mangoes are my favorite fruit.`
- Highlight translation in `I ate yogurt for breakfast.`
- Highlight translation in `We watched the footie match for a while.`
- Highlight translation in `Paracetamol takes up to an hour to work.`
- `Mangoes are my favorite fruit.` 转换成英式英语。
- `I ate yogurt for breakfast.` 转换成英式英语。
- `We had a party at my friend's condo.` 转换成英式英语。
- `Can you toss this in the trashcan for me?` 转换成英式英语。
- `The parking lot was full.` 转换成英式英语。
- `Like a high tech Rube Goldberg machine.` 转换成英式英语。
- `To play hooky means to skip class or work.` 转换成英式英语。
- `No Mr. Bond, I expect you to die.` 转换成英式英语。
- `Dr. Grosh will see you now.` 转换成英式英语。
- `Lunch is at 12:15 today.` 转换成英式英语。
- `We watched the footie match for a while.` 转换成美式英语。
- `Paracetamol takes up to an hour to work.` 转换成美式英语。
- `First, caramelise the onions.` 转换成美式英语。
- `I spent the bank holiday at the funfair.` 转换成美式英语。
- `I had a bicky then went to the chippy.` 转换成美式英语。
- `I've just got bits and bobs in my bum bag.` 转换成美式英语。
- `The car boot sale at Boxted Airfield was called off.` 转换成美式英语。
- `Have you met Mrs Kalyani?` 转换成美式英语。
- `Prof Joyner of King's College, London.` 转换成美式英语。
- `Tea time is usually around 4 or 4.30.` 转换成美式英语。
- `Mangoes are my favorite fruit.` 里的转换高亮。
- 高亮 `I ate yogurt for breakfast.` 里的转换。
- 高亮 `We watched the footie match for a while.` 里的转换。
- 高亮 `Paracetamol takes up to an hour to work.` 里的转换。
Write the following tests in `tests/2_functional-tests.js`:
`tests/2_functional-tests.js` 中写下以下测试:
- Translation with text and locale fields: POST request to `/api/translate`
- Translation with text and invalid locale field: POST request to `/api/translate`
- Translation with missing text field: POST request to `/api/translate`
- Translation with missing locale field: POST request to `/api/translate`
- Translation with empty text: POST request to `/api/translate`
- Translation with text that needs no translation: POST request to `/api/translate`
- 翻译文本字段和本地化字段: POST 请求到 `/api/translate`
- 翻译文本字段和无效的本地化字段: POST 请求到 `/api/translate`
- 翻译缺失的文本字段: POST 请求到 `/api/translate`
- 翻译缺失的本地化字段: POST 请求到 `/api/translate`
- 翻译空的文本: POST 请求到 `/api/translate`
- 翻译无需翻译的文本: POST 请求到 `/api/translate`
# --hints--
I can provide my own project, not the example URL.
我可以提供我自己的项目,而不是示例 URL
```js
(getUserInput) => {
@ -74,7 +74,7 @@ I can provide my own project, not the example URL.
};
```
You can `POST` to `/api/translate` with a body containing `text` with the text to translate and `locale` with either `american-to-british` or `british-to-american`. The returned object should contain the submitted `text` and `translation` with the translated text.
可以向 `/api/translate` 发送 `POST` 请求,对请求体内的 `text` 文本进行翻译, `locale` 字段可以是 `american-to-british` `british-to-american`。 返回的对象应该包含提交的 `text` 以及翻译的文本 `translation`
```js
async (getUserInput) => {
@ -102,7 +102,7 @@ async (getUserInput) => {
};
```
The `/api/translate` route should handle the way time is written in American and British English. For example, ten thirty is written as "10.30" in British English and "10:30" in American English. The `span` element should wrap the entire time string, i.e. `<span class="highlight">10:30</span>`.
`/api/translate` 路由应该可以处理用英美方式英语写的时间。 例如十点半英式英语写为“10.30”而美式英语写为“10:30”。 `span` 元素应该包裹整个时间字符串,即 `<span class="highlight">10:30</span>`
```js
async (getUserInput) => {
@ -129,7 +129,7 @@ async (getUserInput) => {
};
```
The `/api/translate` route should also handle the way titles/honorifics are abbreviated in American and British English. For example, Doctor Wright is abbreviated as "Dr Wright" in British English and "Dr. Wright" in American English. See `/public/american-to-british-titles.js` for the different titles your application should handle.
`/api/translate` 路由也应该处理美式英语和英式英语中头衔/尊称的缩写方式。 例如Doctor Wright 在英式英语中缩写为 “Dr Wright”在美式英语中缩写为 “Dr. Wright"”。 查看 `/public/american-to-british-titles.js` 了应用程序应该处理的不同的头衔。
```js
async (getUserInput) => {
@ -156,7 +156,7 @@ async (getUserInput) => {
};
```
Wrap any translated spelling or terms with `<span class="highlight">...</span>` tags so they appear in green.
将任何翻译过的拼写或条目放在 `<span class="highlight">...</span>` 标签内以使其显示为绿色。
```js
async (getUserInput) => {
@ -184,7 +184,7 @@ async (getUserInput) => {
};
```
If one or more of the required fields is missing, return `{ error: 'Required field(s) missing' }`.
如果缺少一个或多个必填字段,返回 `{ error: 'Required field(s) missing' }`
```js
async (getUserInput) => {
@ -205,7 +205,7 @@ async (getUserInput) => {
};
```
If `text` is empty, return `{ error: 'No text to translate' }`
如果 `text` 为空,返回 `{ error: 'No text to translate' }`
```js
async (getUserInput) => {
@ -226,7 +226,7 @@ async (getUserInput) => {
};
```
If `locale` does not match one of the two specified locales, return `{ error: 'Invalid value for locale field' }`.
如果 `locale` 与两个指定的 locales 都不匹配,返回 `{ error: 'Invalid value for locale field' }`
```js
async (getUserInput) => {
@ -248,7 +248,7 @@ async (getUserInput) => {
};
```
If `text` requires no translation, return `"Everything looks good to me!"` for the `translation` value.
如果 `text` 不需要翻译,返回的 `translation` 值为`"Everything looks good to me!"`
```js
async (getUserInput) => {
@ -275,7 +275,7 @@ async (getUserInput) => {
};
```
All 24 unit tests are complete and passing. See `/tests/1_unit-tests.js` for the expected behavior you should write tests for.
所有 24 个单元的测试都已完成并通过。 请参阅 `/tests/1_unit-tests.js` 来了解你应该写的测试的预期行为。
```js
async (getUserInput) => {
@ -300,7 +300,7 @@ async (getUserInput) => {
};
```
All 6 functional tests are complete and passing. See `/tests/2_functional-tests.js` for the functionality you should write tests for.
所有 6 项功能测试都已完成并通过。 请参阅 `/tests/2_functional-tests.js` 来了解你应该写的测试的功能。
```js
async (getUserInput) => {

View File

@ -1,6 +1,6 @@
---
id: 587d8249367417b2b2512c42
title: Issue Tracker
title: 问题跟踪器
challengeType: 4
forumTopicId: 301569
dashedName: issue-tracker
@ -8,42 +8,42 @@ dashedName: issue-tracker
# --description--
Build a full stack JavaScript app that is functionally similar to this: <https://issue-tracker.freecodecamp.rocks/>. Working on this project will involve you writing your code using one of the following methods:
构建一个 JavaScript 的全栈应用,在功能上与这个应用相似: <https://issue-tracker.freecodecamp.rocks/>。 可以采用下面的任意一种方式完成这个挑战:
- Clone [this GitHub repo](https://github.com/freeCodeCamp/boilerplate-project-issuetracker/) and complete your project locally.
- Use [this repl.it starter project](https://repl.it/github/freeCodeCamp/boilerplate-project-issuetracker) to complete your project.
- Use a site builder of your choice to complete the project. Be sure to incorporate all the files from our GitHub repo.
- 克隆 [GitHub 仓库](https://github.com/freeCodeCamp/boilerplate-project-issuetracker/) 并在本地完成你的项目。
- 使用 [repl.it 上的初始化项目](https://repl.it/github/freeCodeCamp/boilerplate-project-issuetracker) 来完成项目。
- 使用一个你喜欢的站点生成器来完成项目。 需要确定包含了我们 GitHub 仓库的所有文件。
When you are done, make sure a working demo of your project is hosted somewhere public. Then submit the URL to it in the `Solution Link` field. Optionally, also submit a link to your project's source code in the `GitHub Link` field.
完成本项目后,请将一个正常运行的 demo项目演示托管在可以公开访问的平台。 然后在 `Solution Link` 框中提交你的项目 URL。 此外,还可以将项目的源码提交到 `GitHub Link` 中。
# --instructions--
- Complete the necessary routes in `/routes/api.js`
- Create all of the functional tests in `tests/2_functional-tests.js`
- Copy the `sample.env` file to `.env` and set the variables appropriately
- To run the tests uncomment `NODE_ENV=test` in your `.env` file
- To run the tests in the console, use the command `npm run test`. To open the Repl.it console, press Ctrl+Shift+P (Cmd if on a Mac) and type "open shell"
- `/routes/api.js` 中完成必要的路由
- `tests/2_functional-tests.js` 中创建所有的功能测试
- 复制 `sample.env` 文件到 `.env` 并按需设置变量
- 要运行测试,在 `.env` 文件中取消注释 `NODE_ENV=test`
- 使用 `npm run test` 命令,在 console 运行测试。 按 Ctrl+Shift+P (在 Mac 上是 Cmd+Shift+P) 并输入"open shell",打开 Repl.it 控制台。
Write the following tests in `tests/2_functional-tests.js`:
`tests/2_functional-tests.js` 中编写下以下测试:
- Create an issue with every field: POST request to `/api/issues/{project}`
- Create an issue with only required fields: POST request to `/api/issues/{project}`
- Create an issue with missing required fields: POST request to `/api/issues/{project}`
- View issues on a project: GET request to `/api/issues/{project}`
- View issues on a project with one filter: GET request to `/api/issues/{project}`
- View issues on a project with multiple filters: GET request to `/api/issues/{project}`
- Update one field on an issue: PUT request to `/api/issues/{project}`
- Update multiple fields on an issue: PUT request to `/api/issues/{project}`
- Update an issue with missing `_id`: PUT request to `/api/issues/{project}`
- Update an issue with no fields to update: PUT request to `/api/issues/{project}`
- Update an issue with an invalid `_id`: PUT request to `/api/issues/{project}`
- Delete an issue: DELETE request to `/api/issues/{project}`
- Delete an issue with an invalid `_id`: DELETE request to `/api/issues/{project}`
- Delete an issue with missing `_id`: DELETE request to `/api/issues/{project}`
- 用所有字段创建 issuePOST 请求到 `/api/issues/{project}`
- 用必填字段创建 issuePOST 请求到 `/api/issues/{project}`
- 用缺失必填字段创建 issuePOST 请求到 `/api/issues/{project}`
- 查看 project 里的 issueGET 请求到 `/api/issues/{project}`
- 用 filter 过滤 project 里的 issueGET 请求到 `/api/issues/{project}`
- 用多个 filter 过滤 project 里的 issueGET 请求到 `/api/issues/{project}`
- 更新 issue 里的一个字段PUT 请求到 `/api/issues/{project}`
- 更新 issue 里的多个字段PUT 请求到 `/api/issues/{project}`
- 在缺少 `_id` 字段的情况下更新 issue: PUT 请求到 `/api/issues/{project}`
- 在没有字段更新的情况下调用更新PUT 请求到 `/api/issues/{project}`
- 传入一个无效的的 `_id` 来调用更新PUT 请求到 `/api/issues/{project}`
- 删除一个 issueDELETE 请求到 `/api/issues/{project}`
- 传入一个无效的的 `_id` 来调用删除DELETE 请求到 `/api/issues/{project}`
- 在缺失 `_id` 的情况下来调用删除DELETE 请求到 `/api/issues/{project}`
# --hints--
You can provide your own project, not the example URL.
提交自己的项目,而不是示例的 URL
```js
(getUserInput) => {
@ -51,7 +51,7 @@ You can provide your own project, not the example URL.
};
```
You can send a `POST` request to `/api/issues/{projectname}` with form data containing the required fields `issue_title`, `issue_text`, `created_by`, and optionally `assigned_to` and `status_text`.
可以发送 `POST` 请求到 `/api/issues/{projectname}`,表单数据包含必填字段 `issue_title``issue_text``created_by` 和可选字段 `assigned_to` 以及 `status_text`
```js
async (getUserInput) => {
@ -73,7 +73,7 @@ async (getUserInput) => {
};
```
The `POST` request to `/api/issues/{projectname}` will return the created object, and must include all of the submitted fields. Excluded optional fields will be returned as empty strings. Additionally, include `created_on` (date/time), `updated_on` (date/time), `open` (boolean, `true` for open - default value, `false` for closed), and `_id`.
`POST` 请求到 `/api/issues/{projectname}` 将返回创建的对象,必须包含所有提交的全部字段。 如果没有填选填字段将作为空字符串返回. 此外,包含 `created_on` (日期/时间)、 `updated_on` (日期/时间)、 `open` (布尔型) `true` 用于打开 - 默认值, `false` 用于关闭, `_id`
```js
async (getUserInput) => {
@ -107,7 +107,7 @@ async (getUserInput) => {
};
```
If you send a `POST` request to `/api/issues/{projectname}` without the required fields, returned will be the error `{ error: 'required field(s) missing' }`
如果发送一个 `POST` 请求到 `/api/issues/{projectname}` 且缺少必填字段,会返回错误 `{ error: 'required field(s) missing' }`
```js
async (getUserInput) => {
@ -125,7 +125,7 @@ async (getUserInput) => {
};
```
You can send a `GET` request to `/api/issues/{projectname}` for an array of all issues for that specific `projectname`, with all the fields present for each issue.
可以发送 `GET` 请求到 `/api/issues/{projectname}` 请求所有指定 `projectname` 的 issues 数组,会展示每个 issue 的所有字段。
```js
async (getUserInput) => {
@ -172,7 +172,7 @@ async (getUserInput) => {
};
```
You can send a `GET` request to `/api/issues/{projectname}` and filter the request by also passing along any field and value as a URL query (ie. `/api/issues/{project}?open=false`). You can pass one or more field/value pairs at once.
可以发送 `GET` 请求到 `/api/issues/{projectname}` 通过 URL 查询传入字段名和值过滤请求(如, `/api/issues/{project}?open=false`)。 你可以一次通过一个或多个字段/值对。
```js
async (getUserInput) => {
@ -213,7 +213,7 @@ async (getUserInput) => {
};
```
You can send a `PUT` request to `/api/issues/{projectname}` with an `_id` and one or more fields to update. On success, the `updated_on` field should be updated, and returned should be `{ result: 'successfully updated', '_id': _id }`.
你可以发送一个 `PUT` 请求到 `/api/issues/{projectname}` 带有一个 `_id` 以及一个或多个字段进行更新。 成功后, `updated_on` field 应该被更新,返回的应该是 `{ result: 'successfully updated', '_id': _id }`
```js
async (getUserInput) => {
@ -248,7 +248,7 @@ async (getUserInput) => {
};
```
When the `PUT` request sent to `/api/issues/{projectname}` does not include an `_id`, the return value is `{ error: 'missing _id' }`.
`PUT` 请求发送给 `/api/issues/{projectname}` 的请求体不包含 `_id` 时应返回`{ error: 'missing _id' }`
```js
async (getUserInput) => {
@ -264,7 +264,7 @@ async (getUserInput) => {
};
```
When the `PUT` request sent to `/api/issues/{projectname}` does not include update fields, the return value is `{ error: 'no update field(s) sent', '_id': _id }`. On any other error, the return value is `{ error: 'could not update', '_id': _id }`.
`PUT` 请求发送给 `/api/issues/{projectname}` 的请求体不包含任何更新的字段,应返回 `{ error: 'no update field(s) sent', '_id': _id }`。 在任何其他错误,应返回 `{ error: 'could not update', '_id': _id }`
```js
async (getUserInput) => {
@ -294,7 +294,7 @@ async (getUserInput) => {
};
```
You can send a `DELETE` request to `/api/issues/{projectname}` with an `_id` to delete an issue. If no `_id` is sent, the return value is `{ error: 'missing _id' }`. On success, the return value is `{ result: 'successfully deleted', '_id': _id }`. On failure, the return value is `{ error: 'could not delete', '_id': _id }`.
你可以发送一个 `DELETE` 请求到 `/api/issues/{projectname}` 带有一个 `_id` 来删除 issue。 如果没有发送 `_id` ,返回值为 `{ error: 'missing _id' }`。 成功后,返回值为 `{ result: 'successfully deleted', '_id': _id }`。 失败时,返回值为 `{ error: 'could not delete', '_id': _id }`
```js
async (getUserInput) => {
@ -336,7 +336,7 @@ async (getUserInput) => {
};
```
All 14 functional tests are complete and passing.
所有 14 项功能测试都已完成并通过。
```js
async (getUserInput) => {

View File

@ -1,6 +1,6 @@
---
id: 587d8249367417b2b2512c41
title: Metric-Imperial Converter
title: 公制 - 英制转换器
challengeType: 4
forumTopicId: 301570
dashedName: metric-imperial-converter
@ -8,52 +8,52 @@ dashedName: metric-imperial-converter
# --description--
Build a full stack JavaScript app that is functionally similar to this: <https://metric-imperial-converter.freecodecamp.rocks/>. Working on this project will involve you writing your code using one of the following methods:
构建一个 JavaScript 的全栈应用,在功能上与这个应用相似:<https://metric-imperial-converter.freecodecamp.rocks/>。 可以采用下面的任意一种方式完成这个挑战:
- Clone [this GitHub repo](https://github.com/freeCodeCamp/boilerplate-project-metricimpconverter/) and complete your project locally.
- Use [our repl.it starter project](https://repl.it/github/freeCodeCamp/boilerplate-project-metricimpconverter) to complete your project.
- Use a site builder of your choice to complete the project. Be sure to incorporate all the files from our GitHub repo.
- 克隆 [GitHub 仓库](https://github.com/freeCodeCamp/boilerplate-project-metricimpconverter/) 并在本地完成你的项目。
- 使用 [repl.it 上的初始化项目](https://repl.it/github/freeCodeCamp/boilerplate-project-metricimpconverter) 来完成项目。
- 使用一个你喜欢的站点生成器来完成项目。 需要确定包含了我们 GitHub 仓库的所有文件。
When you are done, make sure a working demo of your project is hosted somewhere public. Then submit the URL to it in the `Solution Link` field. Optionally, also submit a link to your project's source code in the `GitHub Link` field.
完成本项目后,请将一个正常运行的 demo项目演示托管在可以公开访问的平台。 然后在 `Solution Link` 框中提交你的项目 URL。 此外,还可以将项目的源码提交到 `GitHub Link` 中。
# --instructions--
- Complete the necessary conversion logic in `/controllers/convertHandler.js`
- Complete the necessary routes in `/routes/api.js`
- Copy the `sample.env` file to `.env` and set the variables appropriately
- To run the tests uncomment `NODE_ENV=test` in your `.env` file
- To run the tests in the console, use the command `npm run test`. To open the Repl.it console, press Ctrl+Shift+P (Cmd if on a Mac) and type "open shell"
- `/controllers/convertHandler.js` 中完成必要的转换逻辑
- `/routes/api.js` 中完成必要的路由
- 复制 `sample.env` 文件到 `.env` 并按需设置变量
- `.env` 文件中取消注释 `NODE_ENV=test` 来运行测试
- 使用 `npm run test` 命令在 console 中运行测试。 按 Ctrl+Shift+P (在 Mac 上是 Cmd+Shift+P) 并输入"open shell",打开 Repl.it 控制台。
Write the following tests in `tests/1_unit-tests.js`:
`tests/1_unit-tests.js` 中写下以下测试:
- `convertHandler` should correctly read a whole number input.
- `convertHandler` should correctly read a decimal number input.
- `convertHandler` should correctly read a fractional input.
- `convertHandler` should correctly read a fractional input with a decimal.
- `convertHandler` should correctly return an error on a double-fraction (i.e. `3/2/3`).
- `convertHandler` should correctly default to a numerical input of `1` when no numerical input is provided.
- `convertHandler` should correctly read each valid input unit.
- `convertHandler` should correctly return an error for an invalid input unit.
- `convertHandler` should return the correct return unit for each valid input unit.
- `convertHandler` should correctly return the spelled-out string unit for each valid input unit.
- `convertHandler` should correctly convert `gal` to `L`.
- `convertHandler` should correctly convert `L` to `gal`.
- `convertHandler` should correctly convert `mi` to `km`.
- `convertHandler` should correctly convert `km` to `mi`.
- `convertHandler` should correctly convert `lbs` to `kg`.
- `convertHandler` should correctly convert `kg` to `lbs`.
- `convertHandler` 应该正确地读取整个数字输入。
- `convertHandler` 应该正确地读取十进制数字输入。
- `convertHandler` 应该正确地读取一个分数输入。
- `convertHandler` 应该正确地读取一个带小数点的分数输入。
- `convertHandler` 当输入双分数时应该返回错误 ( `3/2/3`)
- `convertHandler` 在没有提供数字输入时应该默认为 `1`
- `convertHandler` 应该正确地读取每个有效的单位输入。
- `convertHandler` 在输入无效单位时应返回错误。
- `convertHandler` 在输入有效单位时应返回正确的单位。
- `convertHandler` 应该正确返回每个有效输入单位的拼写字符串。
- `convertHandler` 应该正确地将 `gal` 转换为 `L`
- `convertHandler` 应该正确地将 `L` 转换为 `gal`
- `convertHandler` 应该正确地将 `mi` 转换为 `km`
- `convertHandler` 应该正确地将 `km` 转换为 `mi`
- `convertHandler` 应该正确地将 `lbs` 转换为 `kg`
- `convertHandler` 应该正确地将 `kg` 转换为 `lbs`
Write the following tests in `tests/2_functional-tests.js`:
`tests/2_functional-tests.js` 中写下以下测试:
- Convert a valid input such as `10L`: `GET` request to `/api/convert`.
- Convert an invalid input such as `32g`: `GET` request to `/api/convert`.
- Convert an invalid number such as `3/7.2/4kg`: `GET` request to `/api/convert`.
- Convert an invalid number AND unit such as `3/7.2/4kilomegagram`: `GET` request to `/api/convert`.
- Convert with no number such as `kg`: `GET` request to `/api/convert`.
- 将有效的输入转换为 `10L`: `GET` 请求到 `/api/convert`
- 转换无效的输如 `32g`: `GET` 请求到 `/api/convert`.
- 转换无效的数字,例如 `3/7.2/4kg`: `GET` 请求到 `/api/convert`
- 转换无效的数字和单位如 `3/7.2/4kilomegagram`: `GET` 请求到 `/api/convert`.
- 转换时没有数字,例如 `kg`: `GET` 请求到 `/api/convert`
# --hints--
You can provide your own project, not the example URL.
提交自己的项目,而不是示例的 URL
```js
getUserInput => {
@ -65,11 +65,13 @@ getUserInput => {
};
```
You can `GET` `/api/convert` with a single parameter containing an accepted number and unit and have it converted. (Hint: Split the input by looking for the index of the first character which will mark the start of the unit)
通过 `GET` 请求 `/api/convert`,传入数字和单位的单个参数,可以将其转换。 (提示:通过寻找第一个字符的索引来分割输入,这将标记单位的开始)
```js
```
You can convert `'gal'` to `'L'` and vice versa. (1 gal to 3.78541 L)
可以将 `'gal'` 转换为 `'L'`,反之亦然。 (1 gal to 3.78541 L)
```js
async getUserInput => {
@ -92,7 +94,7 @@ async getUserInput => {
};
```
You can convert `'lbs'` to `'kg'` and vice versa. (1 lbs to 0.453592 kg)
可以将 `'lbs'` 转换为 `'kg'`,反之亦然。 (1 lbs to 0.453592 kg)
```js
async getUserInput => {
@ -115,7 +117,7 @@ async getUserInput => {
};
```
You can convert `'mi'` to `'km'` and vice versa. (1 mi to 1.60934 km)
你可以将 `'mi'` 转换为 `'km'` 反之亦然。 (1 mi to 1.60934 km)
```js
async getUserInput => {
@ -138,7 +140,7 @@ async getUserInput => {
};
```
All incoming units should be accepted in both upper and lower case, but should be returned in both the `initUnit` and `returnUnit` in lower case, except for liter, which should be represented as an uppercase `'L'`.
所有输入单位以大写和小写形式都应该被接受,但在 `initUnit` `returnUnit` 中应以小写形式返回,升除外,应将其表示为大写的 `'L'`
```js
async getUserInput => {
@ -161,7 +163,7 @@ async getUserInput => {
};
```
If the unit of measurement is invalid, returned will be `'invalid unit'`.
如果测量单位无效,返回将为 `'invalid unit'`
```js
async getUserInput => {
@ -174,7 +176,7 @@ async getUserInput => {
};
```
If the number is invalid, returned will be `'invalid number'`.
如果数字无效,返回将为 `'invalid number'`
```js
async getUserInput => {
@ -189,7 +191,7 @@ async getUserInput => {
};
```
If both the unit and number are invalid, returned will be `'invalid number and unit'`.
如果单位和数字都无效,返回将为 `'invalid number and unit'`
```js
async getUserInput => {
@ -207,7 +209,7 @@ async getUserInput => {
};
```
You can use fractions, decimals or both in the parameter (ie. 5, 1/2, 2.5/6), but if nothing is provided it will default to 1.
可以在参数中使用分数、小数或小数分数 (例如 5, 1/2, 2.5/6),如果没有提供任何内容,则默认值为 1
```js
async getUserInput => {
@ -238,7 +240,7 @@ async getUserInput => {
};
```
Your return will consist of the `initNum`, `initUnit`, `returnNum`, `returnUnit`, and `string` spelling out units in the format `'{initNum} {initUnitString} converts to {returnNum} {returnUnitString}'` with the result rounded to 5 decimals.
返回将包含 `initNum``initUnit``returnNum``returnUnit` `string` 拼写单位格式 `'{initNum} {initUnitString} converts to {returnNum} {returnUnitString}'` 结果四舍五入为 5 小数。
```js
async getUserInput => {
@ -255,7 +257,7 @@ async getUserInput => {
};
```
All 16 unit tests are complete and passing.
所有 16 个单元的测试都已完成并通过。
```js
async getUserInput => {
@ -280,7 +282,7 @@ async getUserInput => {
};
```
All 5 functional tests are complete and passing.
所有 5 项功能测试都已完成并通过。
```js
async getUserInput => {

View File

@ -1,6 +1,6 @@
---
id: 587d824a367417b2b2512c43
title: Personal Library
title: 个人图书馆
challengeType: 4
forumTopicId: 301571
dashedName: personal-library
@ -8,25 +8,25 @@ dashedName: personal-library
# --description--
Build a full stack JavaScript app that is functionally similar to this: <https://personal-library.freecodecamp.rocks/>. Working on this project will involve you writing your code using one of the following methods:
构建一个 JavaScript 的全栈应用,在功能上与这个应用相似:<https://personal-library.freecodecamp.rocks/>。 可以采用下面的任意一种方式完成这个挑战:
- Clone [this GitHub repo](https://github.com/freeCodeCamp/boilerplate-project-library) and complete your project locally.
- Use [our repl.it starter project](https://repl.it/github/freeCodeCamp/boilerplate-project-library)) to complete your project.
- Use a site builder of your choice to complete the project. Be sure to incorporate all the files from our GitHub repo.
- 克隆 [这个 GitHub 仓库](https://github.com/freeCodeCamp/boilerplate-project-library) 并在本地完成项目。
- 使用 [repl.it 上的初始化项目](https://repl.it/github/freeCodeCamp/boilerplate-project-library) 来完成项目。
- 使用一个你喜欢的站点生成器来完成项目。 需要确定包含了我们 GitHub 仓库的所有文件。
When you are done, make sure a working demo of your project is hosted somewhere public. Then submit the URL to it in the `Solution Link` field. Optionally, also submit a link to your project's source code in the `GitHub Link` field.
完成本项目后,请将一个正常运行的 demo项目演示托管在可以公开访问的平台。 然后在 `Solution Link` 框中提交你的项目 URL。 此外,还可以将项目的源码提交到 `GitHub Link` 中。
# --instructions--
1. Add your MongoDB connection string to `.env` without quotes as `DB`
Example: `DB=mongodb://admin:pass@1234.mlab.com:1234/fccpersonallib`
2. In your `.env` file set `NODE_ENV` to `test`, without quotes
3. You need to create all routes within `routes/api.js`
4. You will create all functional tests in `tests/2_functional-tests.js`
1. 将的 MongoDB 连接字符串添加到 `.env` 中(没有引号),`DB`
示例: `DB=mongodb://admin:pass@1234.mlab.com:1234/fccpersonallib`
2. `.env` 文件中设置 `NODE_ENV` `test`中,没有引号
3. 需要在 `routes/api.js` 中创建所有路由
4. `tests/2_functional-tests.js` 中创建所有的功能测试
# --hints--
You can provide your own project, not the example URL.
提交自己的项目,而不是示例的 URL
```js
(getUserInput) => {
@ -36,7 +36,7 @@ You can provide your own project, not the example URL.
};
```
You can send a <b>POST</b> request to `/api/books` with `title` as part of the form data to add a book. The returned response will be an object with the `title` and a unique `_id` as keys. If `title` is not included in the request, the returned response should be the string `missing required field title`.
可以发送 <b>POST</b> 请求到 `/api/books`,带有 `title` 作为表单数据的一部分,来添加一本书。 返回的响应将是一个包含 `title` 和唯一的 `_id` 作为键的对象。 如果 `title` 未包含在请求中,返回的响应应该是字符串 `missing required field title`
```js
async (getUserInput) => {
@ -57,7 +57,7 @@ async (getUserInput) => {
};
```
You can send a <b>GET</b> request to `/api/books` and receive a JSON response representing all the books. The JSON response will be an array of objects with each object (book) containing `title`, `_id`, and `commentcount` properties.
可以向 `/api/books` 发送 <b>GET</b> 请求,并返回代表所有书的 JSON 响应。 JSON 响应应该是一个包含有 `title``_id` `commentcount` 属性的对象数组 。
```js
async (getUserInput) => {
@ -85,7 +85,7 @@ async (getUserInput) => {
};
```
You can send a <b>GET</b> request to `/api/books/{_id}` to retrieve a single object of a book containing the properties `title`, `_id`, and a `comments` array (empty array if no comments present). If no book is found, return the string `no book exists`.
可以发送 <b>GET</b> 请求到 `/api/books/{_id}` 来检索一本书的单个对象,返回属性 `title``_id` `comments` 数组 (如果没有评论,则展示空数组)。 如果找不到书, 返回字符串 `no book exists`
```js
async (getUserInput) => {
@ -109,7 +109,7 @@ async (getUserInput) => {
};
```
You can send a <b>POST</b> request containing `comment` as the form body data to `/api/books/{_id}` to add a comment to a book. The returned response will be the books object similar to <b>GET</b> `/api/books/{_id}` request in an earlier test. If `comment` is not included in the request, return the string `missing required field comment`. If no book is found, return the string `no book exists`.
可以发送一个 <b>POST</b> 请求,其中包含 `comment` 作为表单正文数据,请求到 `/api/books/{_id}` 以便将评论添加到书中。 返回的响应将是书对象,在先前测试中 <b>GET</b> `/api/books/{_id}` 类似。 如果请求中没有包含 `comment` ,返回字符串 `missing required field comment`。 如果找不到书, 返回字符串 `no book exists`
```js
async (getUserInput) => {
@ -147,7 +147,7 @@ async (getUserInput) => {
};
```
You can send a <b>DELETE</b> request to `/api/books/{_id}` to delete a book from the collection. The returned response will be the string `delete successful` if successful. If no book is found, return the string `no book exists`.
可以向 `/api/books/{_id}` 发送 <b>DELETE</b> 请求,从收藏中删除一本书。 如果成功,返回的响应将是字符串 `delete successful`。 如果找不到书, 返回字符串 `no book exists`
```js
async (getUserInput) => {
@ -171,7 +171,7 @@ async (getUserInput) => {
};
```
You can send a <b>DELETE</b> request to `/api/books` to delete all books in the database. The returned response will be the string `'complete delete successful` if successful.
可以向 `/api/books` 发送 <b>DELETE</b> 请求来删除数据库中的所有书籍。 如果成功,返回的响应将是字符串 `'complete delete successful`
```js
async (getUserInput) => {
@ -188,7 +188,7 @@ async (getUserInput) => {
};
```
All 10 functional tests required are complete and passing.
所有 10 项功能测试都已完成并通过。
```js
async (getUserInput) => {

View File

@ -1,66 +1,66 @@
---
id: 5e601bf95ac9d0ecd8b94afd
title: Sudoku Solver
title: 数独求解器
challengeType: 4
dashedName: sudoku-solver
---
# --description--
Build a full stack JavaScript app that is functionally similar to this: <https://sudoku-solver.freecodecamp.rocks/>. Working on this project will involve you writing your code using one of the following methods:
构建一个 JavaScript 的全栈应用,在功能上与这个应用相似:<https://sudoku-solver.freecodecamp.rocks/>。 可以采用下面的任意一种方式完成这个挑战:
- Clone [this GitHub repo](https://github.com/freecodecamp/boilerplate-project-sudoku-solver) and complete your project locally.
- Use [our repl.it starter project](https://repl.it/github/freeCodeCamp/boilerplate-project-sudoku-solver) to complete your project.
- Use a site builder of your choice to complete the project. Be sure to incorporate all the files from our GitHub repo.
- 克隆 [GitHub 仓库](https://github.com/freecodecamp/boilerplate-project-sudoku-solver) 并在本地完成你的项目。
- 使用 [repl.it 初始化项目](https://repl.it/github/freeCodeCamp/boilerplate-project-sudoku-solver) 来完成项目。
- 使用一个你喜欢的站点生成器来完成项目。 需要确定包含了我们 GitHub 仓库的所有文件。
When you are done, make sure a working demo of your project is hosted somewhere public. Then submit the URL to it in the `Solution Link` field. Optionally, also submit a link to your project's source code in the `GitHub Link` field.
完成本项目后,请将一个正常运行的 demo项目演示托管在可以公开访问的平台。 然后在 `Solution Link` 框中提交你的项目 URL。 此外,还可以将项目的源码提交到 `GitHub Link` 中。
# --instructions--
- All puzzle logic can go into `/controllers/sudoku-solver.js`
- The `validate` function should take a given puzzle string and check it to see if it has 81 valid characters for the input.
- The `check` functions should be validating against the *current* state of the board.
- The `solve` function should handle solving any given valid puzzle string, not just the test inputs and solutions. You are expected to write out the logic to solve this.
- All routing logic can go into `/routes/api.js`
- See the `puzzle-strings.js` file in `/controllers` for some sample puzzles your application should solve
- To run the challenge tests on this page, set `NODE_ENV` to `test` without quotes in the `.env` file
- To run the tests in the console, use the command `npm run test`. To open the Repl.it console, press Ctrl+Shift+P (Cmd if on a Mac) and type "open shell"
- 所有解谜逻辑都可以进入 `/controllers/sudoku-solver.js`
- `validate` 函数应该使用给定的解谜字符串,然后检查它是否是 81 个有效的输入字符。
- `check` 函数应对棋盘的 *current* 进行验证。
- `solve` 函数应该处理任何给定的解谜字符串,而不仅仅是测试输入和解决方法。 你需要写出解决这个问题的逻辑。
- 所有路由逻辑都可以进入 `/routes/api.js`
- 阅读 `/controllers` 中的 `puzzle-strings.js` 文件来了解一些应用程序应该解决的示例谜题
- `.env` 文件中将 `NODE_ENV` 设置为 `test` (没有引号),运行这个页面的挑战测试。
- 使用 `npm run test` 命令在 console 中运行测试。 按 Ctrl+Shift+P (在 Mac 上是 Cmd+Shift+P) 并输入"open shell",打开 Repl.it 控制台。
Write the following tests in `tests/1_unit-tests.js`:
`tests/1_unit-tests.js` 中写下以下测试:
- Logic handles a valid puzzle string of 81 characters
- Logic handles a puzzle string with invalid characters (not 1-9 or `.`)
- Logic handles a puzzle string that is not 81 characters in length
- Logic handles a valid row placement
- Logic handles an invalid row placement
- Logic handles a valid column placement
- Logic handles an invalid column placement
- Logic handles a valid region (3x3 grid) placement
- Logic handles an invalid region (3x3 grid) placement
- Valid puzzle strings pass the solver
- Invalid puzzle strings fail the solver
- Solver returns the the expected solution for an incomplete puzzzle
- 逻辑处理 81 个字符的解谜字符串
- 逻辑处理无效的解谜字符串 (不是 1-9 `.`)
- 逻辑处理一个长度不是 81 个字符的解谜字符串
- 逻辑处理有效行的位置
- 逻辑处理无效行的位置
- 逻辑处理一个有效的列位置
- 逻辑处理无效列位置
- 逻辑处理一个有效的区域 (3x3 网格)
- 逻辑处理一个无效的区域 (3x3 网格)
- 有效解谜字符串通过 solver
- 无效解谜字符串无法通过 solver
- solver 返回一个不完整谜题的的预期解决方案
Write the following tests in `tests/2_functional-tests.js`
`tests/2_functional-tests.js` 中编写下以下测试:
- Solve a puzzle with valid puzzle string: POST request to `/api/solve`
- Solve a puzzle with missing puzzle string: POST request to `/api/solve`
- Solve a puzzle with invalid characters: POST request to `/api/solve`
- Solve a puzzle with incorrect length: POST request to `/api/solve`
- Solve a puzzle that cannot be solved: POST request to `/api/solve`
- Check a puzzle placement with all fields: POST request to `/api/check`
- Check a puzzle placement with single placement conflict: POST request to `/api/check`
- Check a puzzle placement with multiple placement conflicts: POST request to `/api/check`
- Check a puzzle placement with all placement conflicts: POST request to `/api/check`
- Check a puzzle placement with missing required fields: POST request to `/api/check`
- Check a puzzle placement with invalid characters: POST request to `/api/check`
- Check a puzzle placement with incorrect length: POST request to `/api/check`
- Check a puzzle placement with invalid placement coordinate: POST request to `/api/check`
- Check a puzzle placement with invalid placement value: POST request to `/api/check`
- 用有效的解谜字符串解决一个谜题POST 请求到 `/api/solve`
- 用缺失的解谜字符串解决一个谜题POST 请求到 `/api/solve`
- 用无效字符解决一个谜题POST 请求到 `/api/solve`
- 用不正确的长度解决一个谜题POST 请求到 `/api/solve`
- 解决一个无法解决的谜题POST 请求到 `/api/solve`
- 检查所有字段的解谜位置POST 请求到 `/api/check`
- 用单个位置冲突检查解谜位置POST 请求到 `/api/check`
- 检查一个有多个位置冲突的解谜位置: POST 请求到 `/api/check`
- 检查与所有位置冲突的解谜位置: POST 请求到 `/api/check`
- 检查缺失所需字段的解谜位置POST 请求到 `/api/check`
- 检查一个有无效字符的解谜位置: POST 请求到 `/api/check`
- 检查不正确长度的解谜位置POST 请求到 `/api/check`
- 检查一个无效的放置坐标的解谜位置POST 请求到 `/api/check`
- 检查具有无效的放置值的解谜位置POST 请求到 `/api/check`
# --hints--
You should provide your own project, not the example URL.
提交自己的项目,而不是示例的 URL
```js
(getUserInput) => {
@ -69,7 +69,7 @@ You should provide your own project, not the example URL.
};
```
You can `POST` `/api/solve` with form data containing `puzzle` which will be a string containing a combination of numbers (1-9) and periods `.` to represent empty spaces. The returned object will contain a `solution` property with the solved puzzle.
可以发送 `POST` 请求到 `/api/solve`,使用包含 `puzzle` 的表单数据这将是一个包含数字 (1-9) 和点号的字符串组合,`.` 表示空格。 返回的对象将包含一个 `solution` 属性与解决的谜题。
```js
async (getUserInput) => {
@ -88,7 +88,7 @@ async (getUserInput) => {
};
```
If the object submitted to `/api/solve` is missing `puzzle`, the returned value will be `{ error: 'Required field missing' }`
如果提交给 `/api/solve` 的对象缺失 `puzzle`,返回的值将是 `{ error: 'Required field missing' }`
```js
async (getUserInput) => {
@ -106,7 +106,7 @@ async (getUserInput) => {
};
```
If the puzzle submitted to `/api/solve` contains values which are not numbers or periods, the returned value will be `{ error: 'Invalid characters in puzzle' }`
如果提交给 `/api/solve` 谜题包含非数字或点号的值。 返回的值将是 `{ error: 'Invalid characters in puzzle' }`
```js
async (getUserInput) => {
@ -124,7 +124,7 @@ async (getUserInput) => {
};
```
If the puzzle submitted to `/api/solve` is greater or less than 81 characters, the returned value will be `{ error: 'Expected puzzle to be 81 characters long' }`
如果提交给 `/api/solve` 的谜题大于或小于 81 个字符, 返回的值将是 `{ error: 'Expected puzzle to be 81 characters long' }`
```js
async (getUserInput) => {
@ -142,7 +142,7 @@ async (getUserInput) => {
};
```
If the puzzle submitted to `/api/solve` is invalid or cannot be solved, the returned value will be `{ error: 'Puzzle cannot be solved' }`
如果提交给 `/api/solve` 的谜题无效或无法解决, 返回的值将是 `{ error: 'Puzzle cannot be solved' }`
```js
async (getUserInput) => {
@ -160,7 +160,7 @@ async (getUserInput) => {
};
```
You can `POST` to `/api/check` an object containing `puzzle`, `coordinate`, and `value` where the `coordinate` is the letter A-I indicating the row, followed by a number 1-9 indicating the column, and `value` is a number from 1-9.
可以发送 `POST` 请求到 `/api/check`,包含 `puzzle``coordinate` `value` 的对象,其中 `coordinate` 是表示行的字母 A-I后跟表示列的数字 1-9`value` 是 1-9 的数字。
```js
async (getUserInput) => {
@ -179,7 +179,7 @@ async (getUserInput) => {
};
```
The return value from the `POST` to `/api/check` will be an object containing a `valid` property, which is `true` if the number may be placed at the provided coordinate and `false` if the number may not. If false, the returned object will also contain a `conflict` property which is an array containing the strings `"row"`, `"column"`, and/or `"region"` depending on which makes the placement invalid.
发送 `POST` 请求到 `/api/check`,返回值是一个包含 `valid` 属性的对象,如果数字可能放置在提供的坐标中则是 `true`,否则是`false`。 如果错误,返回的对象还将包含一个 `conflict` 属性,它是一个字符串 `"row"``"column"`, 和/或 取决于哪个区域使位置无效的`"region"`
```js
async (getUserInput) => {
@ -202,7 +202,26 @@ async (getUserInput) => {
};
```
If the puzzle submitted to `/api/check` contains values which are not numbers or periods, the returned value will be `{ error: 'Invalid characters in puzzle' }`
如果提交给 `/api/check``value` 已放置在该 `coordinate` 上的 `puzzle`中,如果 `value` 不冲突,则返回的是 `valid` 属性为 `true` 的对象。
```js
async (getUserInput) => {
const input =
'..9..5.1.85.4....2432......1...69.83.9.....6.62.71...9......1945....4.37.4.3..6..';
const coordinate = 'C3';
const value = '2';
const data = await fetch(getUserInput('url') + '/api/check', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ puzzle: input, coordinate, value })
});
const parsed = await data.json();
assert.property(parsed, 'valid');
assert.isTrue(parsed.valid);
};
```
如果提交给 `/api/check` 的谜题包含非数字或点号的值。 返回的值将是 `{ error: 'Invalid characters in puzzle' }`
```js
async (getUserInput) => {
@ -222,7 +241,7 @@ async (getUserInput) => {
};
```
If the puzzle submitted to `/api/check` is greater or less than 81 characters, the returned value will be `{ error: 'Expected puzzle to be 81 characters long' }`
如果提交给 `/api/check` 的谜题大于或小于 81 个字符, 返回的值将是 `{ error: 'Expected puzzle to be 81 characters long' }`
```js
async (getUserInput) => {
@ -242,7 +261,7 @@ async (getUserInput) => {
};
```
If the object submitted to `/api/check` is missing `puzzle`, `coordinate` or `value`, the returned value will be `{ error: Required field(s) missing }`
如果提交给 `/api/check` 的对象缺失 `puzzle``coordinate` `value`,返回的值将是 `{ error: Required field(s) missing }`
```js
async (getUserInput) => {
@ -260,7 +279,7 @@ async (getUserInput) => {
};
```
If the coordinate submitted to `api/check` does not point to an existing grid cell, the returned value will be `{ error: 'Invalid coordinate'}`
如果提交给 `api/check` 的坐标不指向现有的网格单元格, 返回的值将是 `{ error: 'Invalid coordinate'}`
```js
async (getUserInput) => {
@ -280,7 +299,7 @@ async (getUserInput) => {
};
```
If the `value` submitted to `/api/check` is not a number between 1 and 9, the returned values will be `{ error: 'Invalid value' }`
如果提交给 `/api/check``value` 不是一个介于 1 到 9 之间的数字,则返回的值将是 `{ error: 'Invalid value' }`
```js
async (getUserInput) => {
@ -300,7 +319,7 @@ async (getUserInput) => {
};
```
All 12 unit tests are complete and passing. See `/tests/1_unit-tests.js` for the expected behavior you should write tests for.
所有 12 个单元的测试都已完成并通过。 请参阅 `/tests/1_unit-tests.js` 来了解你应该写的测试的预期行为。
```js
async (getUserInput) => {
@ -323,7 +342,7 @@ async (getUserInput) => {
};
```
All 14 functional tests are complete and passing. See `/tests/2_functional-tests.js` for the functionality you should write tests for.
所有 14 项功能测试都已完成并通过。 请参阅 `/tests/2_functional-tests.js` 来了解你应该编写的测试的功能。
```js
async (getUserInput) => {

View File

@ -1,6 +1,6 @@
---
id: a6b0bb188d873cb2c8729495
title: Convert HTML Entities
title: Convierte entidades HTML
challengeType: 5
forumTopicId: 16007
dashedName: convert-html-entities
@ -8,17 +8,17 @@ dashedName: convert-html-entities
# --description--
Convert the characters `&`, `<`, `>`, `"` (double quote), and `'` (apostrophe), in a string to their corresponding HTML entities.
Convierte los caracteres `&`, `<`, `>`, `"` (dobles comillas), y `'` (apóstrofo), en un cadena con su correspondiente entidad HTML.
# --hints--
`convertHTML("Dolce & Gabbana")` should return `"Dolce &amp; Gabbana"`.
`convertHTML("Dolce & Gabbana")` debe devolver la cadena `Dolce &amp; Gabbana`.
```js
assert.match(convertHTML('Dolce & Gabbana'), /Dolce &amp; Gabbana/);
```
`convertHTML("Hamburgers < Pizza < Tacos")` should return `"Hamburgers &lt; Pizza &lt; Tacos"`.
`convertHTML("Hamburgers < Pizza < Tacos")` debe devolver la cadena `Hamburgers &lt; Pizza &lt; Tacos`.
```js
assert.match(
@ -27,13 +27,13 @@ assert.match(
);
```
`convertHTML("Sixty > twelve")` should return `"Sixty &gt; twelve"`.
`convertHTML("Sixty > twelve")` debe devolver la cadena `Sixty &gt; twelve`.
```js
assert.match(convertHTML('Sixty > twelve'), /Sixty &gt; twelve/);
```
`convertHTML('Stuff in "quotation marks"')` should return `"Stuff in &quot;quotation marks&quot;"`.
`convertHTML('Stuff in "quotation marks"')` debe devolver la cadena `Stuff in &quot;quotation marks&quot;`.
```js
assert.match(
@ -42,19 +42,19 @@ assert.match(
);
```
`convertHTML("Schindler's List")` should return `"Schindler&apos;s List"`.
`convertHTML("Schindler's List")` debe devolver la cadena `Schindler&apos;s List`.
```js
assert.match(convertHTML("Schindler's List"), /Schindler&apos;s List/);
```
`convertHTML("<>")` should return `"&lt;&gt;"`.
`convertHTML("<>")` debe devolver la cadena `&lt;&gt;`.
```js
assert.match(convertHTML('<>'), /&lt;&gt;/);
```
`convertHTML("abc")` should return `"abc"`.
`convertHTML("abc")` debe devolver la cadena `abc`.
```js
assert.strictEqual(convertHTML('abc'), 'abc');

View File

@ -1,6 +1,6 @@
---
id: a5de63ebea8dbee56860f4f2
title: Diff Two Arrays
title: Diferencia entre dos arreglos
challengeType: 5
forumTopicId: 16008
dashedName: diff-two-arrays
@ -8,20 +8,19 @@ dashedName: diff-two-arrays
# --description--
Compare two arrays and return a new array with any items only found in one of the two given arrays, but not both. In other words, return the symmetric difference of the two arrays.
Compara dos arreglos y devuelve un nuevo arreglo con los elementos que sólo se encuentran en uno de los dos arreglos dados, pero no en ambos. En otras palabras, devuelve la diferencia simétrica de los dos arreglos.
**Note**
You can return the array with its elements in any order.
**Nota:**Puedes devolver el arreglo con sus elementos en cualquier orden.
# --hints--
`diffArray([1, 2, 3, 5], [1, 2, 3, 4, 5])` should return an array.
`diffArray([1, 2, 3, 5], [1, 2, 3, 4, 5])` debe devolver un arreglo.
```js
assert(typeof diffArray([1, 2, 3, 5], [1, 2, 3, 4, 5]) === 'object');
```
`["diorite", "andesite", "grass", "dirt", "pink wool", "dead shrub"], ["diorite", "andesite", "grass", "dirt", "dead shrub"]` should return `["pink wool"]`.
`["diorite", "andesite", "grass", "dirt", "pink wool", "dead shrub"], ["diorite", "andesite", "grass", "dirt", "dead shrub"]` debe devolver `["pink wool"]`.
```js
assert.sameMembers(
@ -33,7 +32,7 @@ assert.sameMembers(
);
```
`["diorite", "andesite", "grass", "dirt", "pink wool", "dead shrub"], ["diorite", "andesite", "grass", "dirt", "dead shrub"]` should return an array with one item.
`["diorite", "andesite", "grass", "dirt", "pink wool", "dead shrub"], ["diorite", "andesite", "grass", "dirt", "dead shrub"]` debe devolver un arreglo con un elemento.
```js
assert(
@ -44,7 +43,7 @@ assert(
);
```
`["andesite", "grass", "dirt", "pink wool", "dead shrub"], ["diorite", "andesite", "grass", "dirt", "dead shrub"]` should return `["diorite", "pink wool"]`.
`["andesite", "grass", "dirt", "pink wool", "dead shrub"], ["diorite", "andesite", "grass", "dirt", "dead shrub"]` debe devolver `["diorite", "pink wool"]`.
```js
assert.sameMembers(
@ -56,7 +55,7 @@ assert.sameMembers(
);
```
`["andesite", "grass", "dirt", "pink wool", "dead shrub"], ["diorite", "andesite", "grass", "dirt", "dead shrub"]` should return an array with two items.
`["andesite", "grass", "dirt", "pink wool", "dead shrub"], ["diorite", "andesite", "grass", "dirt", "dead shrub"]` debe devolver un arreglo con dos elementos.
```js
assert(
@ -67,7 +66,7 @@ assert(
);
```
`["andesite", "grass", "dirt", "dead shrub"], ["andesite", "grass", "dirt", "dead shrub"]` should return `[]`.
`["andesite", "grass", "dirt", "dead shrub"], ["andesite", "grass", "dirt", "dead shrub"]` debe devolver `[]`.
```js
assert.sameMembers(
@ -79,7 +78,7 @@ assert.sameMembers(
);
```
`["andesite", "grass", "dirt", "dead shrub"], ["andesite", "grass", "dirt", "dead shrub"]` should return an empty array.
`["andesite", "grass", "dirt", "dead shrub"], ["andesite", "grass", "dirt", "dead shrub"]` debe devolver un arreglo vacío.
```js
assert(
@ -90,19 +89,19 @@ assert(
);
```
`[1, 2, 3, 5], [1, 2, 3, 4, 5]` should return `[4]`.
`[1, 2, 3, 5], [1, 2, 3, 4, 5]` debe devolver `[4]`.
```js
assert.sameMembers(diffArray([1, 2, 3, 5], [1, 2, 3, 4, 5]), [4]);
```
`[1, 2, 3, 5], [1, 2, 3, 4, 5]` should return an array with one item.
`[1, 2, 3, 5], [1, 2, 3, 4, 5]` debe devolver un arreglo con un elemento.
```js
assert(diffArray([1, 2, 3, 5], [1, 2, 3, 4, 5]).length === 1);
```
`[1, "calf", 3, "piglet"], [1, "calf", 3, 4]` should return `["piglet", 4]`.
`[1, "calf", 3, "piglet"], [1, "calf", 3, 4]` debe devolver `["piglet", 4]`.
```js
assert.sameMembers(diffArray([1, 'calf', 3, 'piglet'], [1, 'calf', 3, 4]), [
@ -111,13 +110,13 @@ assert.sameMembers(diffArray([1, 'calf', 3, 'piglet'], [1, 'calf', 3, 4]), [
]);
```
`[1, "calf", 3, "piglet"], [1, "calf", 3, 4]` should return an array with two items.
`[1, "calf", 3, "piglet"], [1, "calf", 3, 4]` debe devolver un arreglo con dos elementos.
```js
assert(diffArray([1, 'calf', 3, 'piglet'], [1, 'calf', 3, 4]).length === 2);
```
`[], ["snuffleupagus", "cookie monster", "elmo"]` should return `["snuffleupagus", "cookie monster", "elmo"]`.
`[], ["snuffleupagus", "cookie monster", "elmo"]` debe devolver `["snuffleupagus", "cookie monster", "elmo"]`.
```js
assert.sameMembers(diffArray([], ['snuffleupagus', 'cookie monster', 'elmo']), [
@ -127,13 +126,13 @@ assert.sameMembers(diffArray([], ['snuffleupagus', 'cookie monster', 'elmo']), [
]);
```
`[], ["snuffleupagus", "cookie monster", "elmo"]` should return an array with three items.
`[], ["snuffleupagus", "cookie monster", "elmo"]` debe devolver un arreglo con tres elementos.
```js
assert(diffArray([], ['snuffleupagus', 'cookie monster', 'elmo']).length === 3);
```
`[1, "calf", 3, "piglet"], [7, "filly"]` should return `[1, "calf", 3, "piglet", 7, "filly"]`.
`[1, "calf", 3, "piglet"], [7, "filly"]` debe devolver `[1, "calf", 3, "piglet", 7, "filly"]`.
```js
assert.sameMembers(diffArray([1, 'calf', 3, 'piglet'], [7, 'filly']), [
@ -146,7 +145,7 @@ assert.sameMembers(diffArray([1, 'calf', 3, 'piglet'], [7, 'filly']), [
]);
```
`[1, "calf", 3, "piglet"], [7, "filly"]` should return an array with six items.
`[1, "calf", 3, "piglet"], [7, "filly"]` debe devolver un arreglo con seis elementos.
```js
assert(diffArray([1, 'calf', 3, 'piglet'], [7, 'filly']).length === 6);

View File

@ -1,6 +1,6 @@
---
id: a5deed1811a43193f9f1c841
title: Drop it
title: Déjalo caer
challengeType: 5
forumTopicId: 16010
dashedName: drop-it
@ -8,13 +8,13 @@ dashedName: drop-it
# --description--
Given the array `arr`, iterate through and remove each element starting from the first element (the 0 index) until the function `func` returns `true` when the iterated element is passed through it.
Dado el arreglo `arr`, itera y elimina cada elemento comenzando desde el primer elemento (el índice 0) hasta que la funcn `func` devuelva `true` cuando el elemento iterado se pasa a través de él.
Then return the rest of the array once the condition is satisfied, otherwise, `arr` should be returned as an empty array.
Luego devuelve el resto del arreglo una vez que se cumpla la condición, de lo contrario, `arr` debe devolverse como un arreglo vacío.
# --hints--
`dropElements([1, 2, 3, 4], function(n) {return n >= 3;})` should return `[3, 4]`.
`dropElements([1, 2, 3, 4], function(n) {return n >= 3;})` debe devolver `[3, 4]`.
```js
assert.deepEqual(
@ -25,7 +25,7 @@ assert.deepEqual(
);
```
`dropElements([0, 1, 0, 1], function(n) {return n === 1;})` should return `[1, 0, 1]`.
`dropElements([0, 1, 0, 1], function(n) {return n === 1;})` debe devolver `[1, 0, 1]`.
```js
assert.deepEqual(
@ -36,7 +36,7 @@ assert.deepEqual(
);
```
`dropElements([1, 2, 3], function(n) {return n > 0;})` should return `[1, 2, 3]`.
`dropElements([1, 2, 3], function(n) {return n > 0;})` debe devolver `[1, 2, 3]`.
```js
assert.deepEqual(
@ -47,7 +47,7 @@ assert.deepEqual(
);
```
`dropElements([1, 2, 3, 4], function(n) {return n > 5;})` should return `[]`.
`dropElements([1, 2, 3, 4], function(n) {return n > 5;})` debe devolver `[]`.
```js
assert.deepEqual(
@ -58,7 +58,7 @@ assert.deepEqual(
);
```
`dropElements([1, 2, 3, 7, 4], function(n) {return n > 3;})` should return `[7, 4]`.
`dropElements([1, 2, 3, 7, 4], function(n) {return n > 3;})` debe devolver `[7, 4]`.
```js
assert.deepEqual(
@ -69,7 +69,7 @@ assert.deepEqual(
);
```
`dropElements([1, 2, 3, 9, 2], function(n) {return n > 2;})` should return `[3, 9, 2]`.
`dropElements([1, 2, 3, 9, 2], function(n) {return n > 2;})` debe devolver `[3, 9, 2]`.
```js
assert.deepEqual(

View File

@ -1,6 +1,6 @@
---
id: a10d2431ad0c6a099a4b8b52
title: Everything Be True
title: Todo sea verdad
challengeType: 5
forumTopicId: 16011
dashedName: everything-be-true
@ -8,17 +8,17 @@ dashedName: everything-be-true
# --description--
Check if the predicate (second argument) is <dfn>truthy</dfn> on all elements of a collection (first argument).
Comprueba si el predicado (segundo argumento) es <dfn>truthy</dfn> en todos los elementos de una colección (primer argumento).
In other words, you are given an array collection of objects. The predicate `pre` will be an object property and you need to return `true` if its value is `truthy`. Otherwise, return `false`.
En otras palabras, se te da una colección de arreglos de objetos. El predicado `pre` será una propiedad del objeto y debe devolver `true` si su valor es `truthy`. De lo contrario, devuelve `false`.
In JavaScript, `truthy` values are values that translate to `true` when evaluated in a Boolean context.
En JavaScript, los valores `truthy` son valores que se traducen en `true` cuando se evalúan en un contexto booleano.
Remember, you can access object properties through either dot notation or `[]` notation.
Recuerda, puedes acceder a las propiedades del objeto mediante la notación de puntos o la notación de corchetes `[]`.
# --hints--
`truthCheck([{"user": "Tinky-Winky", "sex": "male"}, {"user": "Dipsy", "sex": "male"}, {"user": "Laa-Laa", "sex": "female"}, {"user": "Po", "sex": "female"}], "sex")` should return true.
`truthCheck([{"user": "Tinky-Winky", "sex": "male"}, {"user": "Dipsy", "sex": "male"}, {"user": "Laa-Laa", "sex": "female"}, {"user": "Po", "sex": "female"}], "sex")` debe devolver `true`.
```js
assert.strictEqual(
@ -35,7 +35,7 @@ assert.strictEqual(
);
```
`truthCheck([{"user": "Tinky-Winky", "sex": "male"}, {"user": "Dipsy"}, {"user": "Laa-Laa", "sex": "female"}, {"user": "Po", "sex": "female"}], "sex")` should return false.
`truthCheck([{"user": "Tinky-Winky", "sex": "male"}, {"user": "Dipsy"}, {"user": "Laa-Laa", "sex": "female"}, {"user": "Po", "sex": "female"}], "sex")` debe devolver `false`.
```js
assert.strictEqual(
@ -52,7 +52,7 @@ assert.strictEqual(
);
```
`truthCheck([{"user": "Tinky-Winky", "sex": "male", "age": 0}, {"user": "Dipsy", "sex": "male", "age": 3}, {"user": "Laa-Laa", "sex": "female", "age": 5}, {"user": "Po", "sex": "female", "age": 4}], "age")` should return false.
`truthCheck([{"user": "Tinky-Winky", "sex": "male", "age": 0}, {"user": "Dipsy", "sex": "male", "age": 3}, {"user": "Laa-Laa", "sex": "female", "age": 5}, {"user": "Po", "sex": "female", "age": 4}], "age")` debe devolver `false`.
```js
assert.strictEqual(
@ -69,7 +69,7 @@ assert.strictEqual(
);
```
`truthCheck([{"name": "Pete", "onBoat": true}, {"name": "Repeat", "onBoat": true}, {"name": "FastForward", "onBoat": null}], "onBoat")` should return false
`truthCheck([{"name": "Pete", "onBoat": true}, {"name": "Repeat", "onBoat": true}, {"name": "FastForward", "onBoat": null}], "onBoat")` debe devolver `false`.
```js
assert.strictEqual(
@ -85,7 +85,7 @@ assert.strictEqual(
);
```
`truthCheck([{"name": "Pete", "onBoat": true}, {"name": "Repeat", "onBoat": true, "alias": "Repete"}, {"name": "FastForward", "onBoat": true}], "onBoat")` should return true
`truthCheck([{"name": "Pete", "onBoat": true}, {"name": "Repeat", "onBoat": true, "alias": "Repete"}, {"name": "FastForward", "onBoat": true}], "onBoat")` debe devolver `true`.
```js
assert.strictEqual(
@ -101,13 +101,13 @@ assert.strictEqual(
);
```
`truthCheck([{"single": "yes"}], "single")` should return true
`truthCheck([{"single": "yes"}], "single")` debe devolver `true`.
```js
assert.strictEqual(truthCheck([{ single: 'yes' }], 'single'), true);
```
`truthCheck([{"single": ""}, {"single": "double"}], "single")` should return false
`truthCheck([{"single": ""}, {"single": "double"}], "single")` debe devolver `false`.
```js
assert.strictEqual(
@ -116,7 +116,7 @@ assert.strictEqual(
);
```
`truthCheck([{"single": "double"}, {"single": undefined}], "single")` should return false
`truthCheck([{"single": "double"}, {"single": undefined}], "single")` debe devolver `false`.
```js
assert.strictEqual(
@ -125,7 +125,7 @@ assert.strictEqual(
);
```
`truthCheck([{"single": "double"}, {"single": NaN}], "single")` should return false
`truthCheck([{"single": "double"}, {"single": NaN}], "single")` debe devolver `false`.
```js
assert.strictEqual(

View File

@ -1,6 +1,6 @@
---
id: a2f1d72d9b908d0bd72bb9f6
title: Make a Person
title: Crea una persona
challengeType: 5
forumTopicId: 16020
dashedName: make-a-person
@ -8,7 +8,7 @@ dashedName: make-a-person
# --description--
Fill in the object constructor with the following methods below:
Completa el constructor de objetos con los siguientes métodos:
```js
getFirstName()
@ -19,53 +19,53 @@ setLastName(last)
setFullName(firstAndLast)
```
Run the tests to see the expected output for each method. The methods that take an argument must accept only one argument and it has to be a string. These methods must be the only available means of interacting with the object.
Ejecuta las pruebas para ver el resultado esperado para cada método. Los métodos que toman un argumento deben aceptar sólo un argumento y tiene que ser una cadena. Estos métodos deben ser el único medio disponible para interactuar con el objeto.
# --hints--
`Object.keys(bob).length` should return 6.
`Object.keys(bob).length` debe devolver 6.
```js
assert.deepEqual(Object.keys(bob).length, 6);
```
`bob instanceof Person` should return true.
`bob instanceof Person` debe devolver `true`.
```js
assert.deepEqual(bob instanceof Person, true);
```
`bob.firstName` should return undefined.
`bob.firstName` debe devolver `undefined`.
```js
assert.deepEqual(bob.firstName, undefined);
```
`bob.lastName` should return undefined.
`bob.lastName` debe devolver `undefined`.
```js
assert.deepEqual(bob.lastName, undefined);
```
`bob.getFirstName()` should return "Bob".
`bob.getFirstName()` debe devolver la cadena `Bob`.
```js
assert.deepEqual(bob.getFirstName(), 'Bob');
```
`bob.getLastName()` should return "Ross".
`bob.getLastName()` debe devolver la cadena `Ross`.
```js
assert.deepEqual(bob.getLastName(), 'Ross');
```
`bob.getFullName()` should return "Bob Ross".
`bob.getFullName()` debe devolver la cadena `Bob Ross`.
```js
assert.deepEqual(bob.getFullName(), 'Bob Ross');
```
`bob.getFullName()` should return "Haskell Ross" after `bob.setFirstName("Haskell")`.
`bob.getFullName()` debe devolver la cadena `Haskell Ross` after `bob.setFirstName("Haskell")`.
```js
assert.strictEqual(
@ -77,7 +77,7 @@ assert.strictEqual(
);
```
`bob.getFullName()` should return "Haskell Curry" after `bob.setLastName("Curry")`.
`bob.getFullName()` debe devolver la cadena `Haskell Curry` después de `bob.setLastName("Curry")`.
```js
assert.strictEqual(
@ -90,7 +90,7 @@ assert.strictEqual(
);
```
`bob.getFullName()` should return "Haskell Curry" after `bob.setFullName("Haskell Curry")`.
`bob.getFullName()` debe devolver la cadena `Haskell Curry` después de `bob.setFullName("Haskell Curry")`.
```js
assert.strictEqual(
@ -102,7 +102,7 @@ assert.strictEqual(
);
```
`bob.getFirstName()` should return "Haskell" after `bob.setFullName("Haskell Curry")`.
`bob.getFirstName()` debe devolver la cadena `Haskell` después de `bob.setFullName("Haskell Curry")`.
```js
assert.strictEqual(
@ -114,7 +114,7 @@ assert.strictEqual(
);
```
`bob.getLastName()` should return "Curry" after `bob.setFullName("Haskell Curry")`.
`bob.getLastName()` debe devolver la cadena `Curry` después de `bob.setFullName("Haskell Curry")`.
```js
assert.strictEqual(

View File

@ -1,6 +1,6 @@
---
id: af7588ade1100bde429baf20
title: Missing letters
title: Letras faltantes
challengeType: 5
forumTopicId: 16023
dashedName: missing-letters
@ -8,37 +8,37 @@ dashedName: missing-letters
# --description--
Find the missing letter in the passed letter range and return it.
Encuentra la letra que falta en la siguiente cadena de letras y devuélvela.
If all letters are present in the range, return undefined.
Si todas las letras están presentes en la cadena, devuelve `undefined`.
# --hints--
`fearNotLetter("abce")` should return "d".
`fearNotLetter("abce")` debe devolver la cadena `d`.
```js
assert.deepEqual(fearNotLetter('abce'), 'd');
```
`fearNotLetter("abcdefghjklmno")` should return "i".
`fearNotLetter("abcdefghjklmno")` debe devolver la cadena `i`.
```js
assert.deepEqual(fearNotLetter('abcdefghjklmno'), 'i');
```
`fearNotLetter("stvwx")` should return "u".
`fearNotLetter("stvwx")` debe devolver la cadena `u`.
```js
assert.deepEqual(fearNotLetter('stvwx'), 'u');
```
`fearNotLetter("bcdf")` should return "e".
`fearNotLetter("bcdf")` debe devolver la cadena `e`.
```js
assert.deepEqual(fearNotLetter('bcdf'), 'e');
```
`fearNotLetter("abcdefghijklmnopqrstuvwxyz")` should return undefined.
`fearNotLetter("abcdefghijklmnopqrstuvwxyz")` debe devolver `undefined`.
```js
assert.isUndefined(fearNotLetter('abcdefghijklmnopqrstuvwxyz'));

View File

@ -1,6 +1,6 @@
---
id: aa7697ea2477d1316795783b
title: Pig Latin
title: Pig Latin (Latin de los cerdos)
challengeType: 5
forumTopicId: 16039
dashedName: pig-latin
@ -8,55 +8,55 @@ dashedName: pig-latin
# --description--
Pig Latin is a way of altering English Words. The rules are as follows:
Pig Latin (latin de los cerdos) es una manera de alterar las palabras en inglés. Las normas son las siguientes:
\- If a word begins with a consonant, take the first consonant or consonant cluster, move it to the end of the word, and add "ay" to it.
\- Si una palabra comienza con una consonante, toma la primer consonante o grupo de consonantes, muévela al final de la palabra, y añade `ay` a ella.
\- If a word begins with a vowel, just add "way" at the end.
\- Si una palabra comienza con una vocal, solo añade `way` al final.
# --instructions--
Translate the provided string to Pig Latin. Input strings are guaranteed to be English words in all lowercase.
Traduce la cadena proporcionada a Pig Latin. Las cadenas de entrada están garantizadas como palabras en inglés en minúsculas.
# --hints--
`translatePigLatin("california")` should return "aliforniacay".
`translatePigLatin("california")` debe devolver la cadena `aliforniacay`.
```js
assert.deepEqual(translatePigLatin('california'), 'aliforniacay');
```
`translatePigLatin("paragraphs")` should return "aragraphspay".
`translatePigLatin("paragraphs")` debe devolver la cadena `aragraphspay`.
```js
assert.deepEqual(translatePigLatin('paragraphs'), 'aragraphspay');
```
`translatePigLatin("glove")` should return "oveglay".
`translatePigLatin("glove")` debe devolver la cadena `oveglay`.
```js
assert.deepEqual(translatePigLatin('glove'), 'oveglay');
```
`translatePigLatin("algorithm")` should return "algorithmway".
`translatePigLatin("algorithm")` debe devolver la cadena `algorithmway`.
```js
assert.deepEqual(translatePigLatin('algorithm'), 'algorithmway');
```
`translatePigLatin("eight")` should return "eightway".
`translatePigLatin("eight")` debe devolver la cadena `eightway`.
```js
assert.deepEqual(translatePigLatin('eight'), 'eightway');
```
Should handle words where the first vowel comes in the middle of the word. `translatePigLatin("schwartz")` should return "artzschway".
Debes manejar las palabras en donde la primera vocal viene en el centro de la palabra. `translatePigLatin("schwartz")` debe devolver la cadena `artzschway`.
```js
assert.deepEqual(translatePigLatin('schwartz'), 'artzschway');
```
Should handle words without vowels. `translatePigLatin("rhythm")` should return "rhythmay".
Debes manejar las palabras sin vocales. `translatePigLatin("rhythm")` debe devolver la cadena `rhythmay`.
```js
assert.deepEqual(translatePigLatin('rhythm'), 'rhythmay');

View File

@ -1,6 +1,6 @@
---
id: a0b5010f579e69b815e7c5d6
title: Search and Replace
title: Busca y reemplaza
challengeType: 5
forumTopicId: 16045
dashedName: search-and-replace
@ -8,20 +8,19 @@ dashedName: search-and-replace
# --description--
Perform a search and replace on the sentence using the arguments provided and return the new sentence.
Realiza una búsqueda y reemplaza en la oración usando los argumentos proporcionados y devuelve la nueva oración.
First argument is the sentence to perform the search and replace on.
El primer argumento es la frase sobre la que se va a realizar la búsqueda y el reemplazo.
Second argument is the word that you will be replacing (before).
El segundo argumento es la palabra que se reemplazará (antes).
Third argument is what you will be replacing the second argument with (after).
El tercer argumento es lo que reemplazará el segundo argumento (después).
**Note**
Preserve the case of the first character in the original word when you are replacing it. For example if you mean to replace the word "Book" with the word "dog", it should be replaced as "Dog"
**Note:** Mantén la capitalización del primer carácter en la palabra original cuando lo estés reemplazando. Por ejemplo, si quieres reemplazar la palabra `Book` por la palabra `dog`, debe ser reemplazada como `Dog`
# --hints--
`myReplace("Let us go to the store", "store", "mall")` should return "Let us go to the mall".
`myReplace("Let us go to the store", "store", "mall")` debe devolver la cadena `Let us go to the mall`.
```js
assert.deepEqual(
@ -30,7 +29,7 @@ assert.deepEqual(
);
```
`myReplace("He is Sleeping on the couch", "Sleeping", "sitting")` should return "He is Sitting on the couch".
`myReplace("He is Sleeping on the couch", "Sleeping", "sitting")` debe devolver la cadena `He is Sitting on the couch`.
```js
assert.deepEqual(
@ -39,7 +38,7 @@ assert.deepEqual(
);
```
`myReplace("I think we should look up there", "up", "Down")` should return "I think we should look down there".
`myReplace("I think we should look up there", "up", "Down")` debe devolver la cadena `I think we should look down there`.
```js
assert.deepEqual(
@ -48,7 +47,7 @@ assert.deepEqual(
);
```
`myReplace("This has a spellngi error", "spellngi", "spelling")` should return "This has a spelling error".
`myReplace("This has a spellngi error", "spellngi", "spelling")` debe devolver la cadena `This has a spelling error`.
```js
assert.deepEqual(
@ -57,7 +56,7 @@ assert.deepEqual(
);
```
`myReplace("His name is Tom", "Tom", "john")` should return "His name is John".
`myReplace("His name is Tom", "Tom", "john")` debe devolver la cadena `His name is John`.
```js
assert.deepEqual(
@ -66,7 +65,7 @@ assert.deepEqual(
);
```
`myReplace("Let us get back to more Coding", "Coding", "algorithms")` should return "Let us get back to more Algorithms".
`myReplace("Let us get back to more Coding", "Coding", "algorithms")` debe devolver la cadena `Let us get back to more Algorithms`.
```js
assert.deepEqual(

View File

@ -1,6 +1,6 @@
---
id: a39963a4c10bc8b4d4f06d7e
title: Seek and Destroy
title: Busca y destruye
challengeType: 5
forumTopicId: 16046
dashedName: seek-and-destroy
@ -8,38 +8,37 @@ dashedName: seek-and-destroy
# --description--
You will be provided with an initial array (the first argument in the destroyer function), followed by one or more arguments. Remove all elements from the initial array that are of the same value as these arguments.
Se proporcionará un arreglo inicial (el primer argumento en la función `destroyer`), seguido de uno o más argumentos. Elimina todos los elementos del arreglo inicial que tengan el mismo valor que estos argumentos.
**Note**
You have to use the `arguments` object.
**Nota:** Tienes que utilizar el objeto `arguments`.
# --hints--
`destroyer([1, 2, 3, 1, 2, 3], 2, 3)` should return `[1, 1]`.
`destroyer([1, 2, 3, 1, 2, 3], 2, 3)` debe devolver `[1, 1]`.
```js
assert.deepEqual(destroyer([1, 2, 3, 1, 2, 3], 2, 3), [1, 1]);
```
`destroyer([1, 2, 3, 5, 1, 2, 3], 2, 3)` should return `[1, 5, 1]`.
`destroyer([1, 2, 3, 5, 1, 2, 3], 2, 3)` debe devolver `[1, 5, 1]`.
```js
assert.deepEqual(destroyer([1, 2, 3, 5, 1, 2, 3], 2, 3), [1, 5, 1]);
```
`destroyer([3, 5, 1, 2, 2], 2, 3, 5)` should return `[1]`.
`destroyer([3, 5, 1, 2, 2], 2, 3, 5)` debe devolver `[1]`.
```js
assert.deepEqual(destroyer([3, 5, 1, 2, 2], 2, 3, 5), [1]);
```
`destroyer([2, 3, 2, 3], 2, 3)` should return `[]`.
`destroyer([2, 3, 2, 3], 2, 3)` debe devolver `[]`.
```js
assert.deepEqual(destroyer([2, 3, 2, 3], 2, 3), []);
```
`destroyer(["tree", "hamburger", 53], "tree", 53)` should return `["hamburger"]`.
`destroyer(["tree", "hamburger", 53], "tree", 53)` debe devolver `["hamburger"]`.
```js
assert.deepEqual(destroyer(['tree', 'hamburger', 53], 'tree', 53), [
@ -47,7 +46,7 @@ assert.deepEqual(destroyer(['tree', 'hamburger', 53], 'tree', 53), [
]);
```
`destroyer(["possum", "trollo", 12, "safari", "hotdog", 92, 65, "grandma", "bugati", "trojan", "yacht"], "yacht", "possum", "trollo", "safari", "hotdog", "grandma", "bugati", "trojan")` should return `[12,92,65]`.
`destroyer(["possum", "trollo", 12, "safari", "hotdog", 92, 65, "grandma", "bugati", "trojan", "yacht"], "yacht", "possum", "trollo", "safari", "hotdog", "grandma", "bugati", "trojan")` debe devolver `[12,92,65]`.
```js
assert.deepEqual(

View File

@ -1,6 +1,6 @@
---
id: ae9defd7acaf69703ab432ea
title: Smallest Common Multiple
title: Múltiplo común más pequeño
challengeType: 5
forumTopicId: 16075
dashedName: smallest-common-multiple
@ -8,45 +8,45 @@ dashedName: smallest-common-multiple
# --description--
Find the smallest common multiple of the provided parameters that can be evenly divided by both, as well as by all sequential numbers in the range between these parameters.
Encuentra el múltiplo común más pequeño de los parámetros proporcionados que pueden dividirse equitativamente por ambos, así como por todos los números consecutivos del rango entre estos parámetros.
The range will be an array of two numbers that will not necessarily be in numerical order.
El rango será un arreglo de dos números que no necesariamente estarán en orden numérico.
For example, if given 1 and 3, find the smallest common multiple of both 1 and 3 that is also evenly divisible by all numbers *between* 1 and 3. The answer here would be 6.
Por ejemplo, si se dan 1 y 3, encuentra el múltiplo común más pequeño de 1 y 3 que también es dividido por todos los números *entre* 1 y 3. La respuesta sería 6.
# --hints--
`smallestCommons([1, 5])` should return a number.
`smallestCommons([1, 5])` debe devolver un número.
```js
assert.deepEqual(typeof smallestCommons([1, 5]), 'number');
```
`smallestCommons([1, 5])` should return 60.
`smallestCommons([1, 5])` debe devolver 60.
```js
assert.deepEqual(smallestCommons([1, 5]), 60);
```
`smallestCommons([5, 1])` should return 60.
`smallestCommons([5, 1])` debe devolver 60.
```js
assert.deepEqual(smallestCommons([5, 1]), 60);
```
`smallestCommons([2, 10])` should return 2520.
`smallestCommons([2, 10])` debe devolver 2520.
```js
assert.deepEqual(smallestCommons([2, 10]), 2520);
```
`smallestCommons([1, 13])` should return 360360.
`smallestCommons([1, 13])` debe devolver 360360.
```js
assert.deepEqual(smallestCommons([1, 13]), 360360);
```
`smallestCommons([23, 18])` should return 6056820.
`smallestCommons([23, 18])` debe devolver 6056820.
```js
assert.deepEqual(smallestCommons([23, 18]), 6056820);

View File

@ -1,6 +1,6 @@
---
id: a105e963526e7de52b219be9
title: Sorted Union
title: Unión ordenada
challengeType: 5
forumTopicId: 16077
dashedName: sorted-union
@ -8,29 +8,29 @@ dashedName: sorted-union
# --description--
Write a function that takes two or more arrays and returns a new array of unique values in the order of the original provided arrays.
Escribe una función que tome dos o más arreglos y devuelve un nuevo arreglo de valores únicos manteniendo el orden original de los arreglos proporcionados.
In other words, all values present from all arrays should be included in their original order, but with no duplicates in the final array.
En otras palabras, todos los valores presentes de todos los arreglos deben incluirse en su orden original, pero sin duplicados en el arreglo final.
The unique numbers should be sorted by their original order, but the final array should not be sorted in numerical order.
Los números únicos deben ser ordenados según su orden original, pero el arreglo final no debe ordenarse según el orden numérico.
Check the assertion tests for examples.
Revisa las pruebas de afirmación para ver ejemplos.
# --hints--
`uniteUnique([1, 3, 2], [5, 2, 1, 4], [2, 1])` should return `[1, 3, 2, 5, 4]`.
`uniteUnique([1, 3, 2], [5, 2, 1, 4], [2, 1])` debe devolver `[1, 3, 2, 5, 4]`.
```js
assert.deepEqual(uniteUnique([1, 3, 2], [5, 2, 1, 4], [2, 1]), [1, 3, 2, 5, 4]);
```
`uniteUnique([1, 2, 3], [5, 2, 1])` should return `[1, 2, 3, 5]`.
`uniteUnique([1, 2, 3], [5, 2, 1])` debe devolver `[1, 2, 3, 5]`.
```js
assert.deepEqual(uniteUnique([1, 2, 3], [5, 2, 1]), [1, 2, 3, 5]);
```
`uniteUnique([1, 2, 3], [5, 2, 1, 4], [2, 1], [6, 7, 8])` should return `[1, 2, 3, 5, 4, 6, 7, 8]`.
`uniteUnique([1, 2, 3], [5, 2, 1, 4], [2, 1], [6, 7, 8])` debe devolver `[1, 2, 3, 5, 4, 6, 7, 8]`.
```js
assert.deepEqual(uniteUnique([1, 2, 3], [5, 2, 1, 4], [2, 1], [6, 7, 8]), [

View File

@ -1,6 +1,6 @@
---
id: a103376db3ba46b2d50db289
title: Spinal Tap Case
title: Spinal case
challengeType: 5
forumTopicId: 16078
dashedName: spinal-tap-case
@ -8,23 +8,23 @@ dashedName: spinal-tap-case
# --description--
Convert a string to spinal case. Spinal case is all-lowercase-words-joined-by-dashes.
Convierte una cadena a spinal case. Spinal case significa todas-las-palabras-en-minúscula-unidas-por-guiones.
# --hints--
`spinalCase("This Is Spinal Tap")` should return `"this-is-spinal-tap"`.
`spinalCase("This Is Spinal Tap")` debe devolver la cadena `this-is-spinal-tap`.
```js
assert.deepEqual(spinalCase('This Is Spinal Tap'), 'this-is-spinal-tap');
```
`spinalCase("thisIsSpinalTap")` should return `"this-is-spinal-tap"`.
`spinalCase("thisIsSpinalTap")` debe devolver la cadena `this-is-spinal-tap`.
```js
assert.strictEqual(spinalCase('thisIsSpinalTap'), 'this-is-spinal-tap');
```
`spinalCase("The_Andy_Griffith_Show")` should return `"the-andy-griffith-show"`.
`spinalCase("The_Andy_Griffith_Show")` debe devolver la cadena `the-andy-griffith-show`.
```js
assert.strictEqual(
@ -33,7 +33,7 @@ assert.strictEqual(
);
```
`spinalCase("Teletubbies say Eh-oh")` should return `"teletubbies-say-eh-oh"`.
`spinalCase("Teletubbies say Eh-oh")` debe devolver la cadena `teletubbies-say-eh-oh`.
```js
assert.strictEqual(
@ -42,7 +42,7 @@ assert.strictEqual(
);
```
`spinalCase("AllThe-small Things")` should return `"all-the-small-things"`.
`spinalCase("AllThe-small Things")` debe devolver la cadena `all-the-small-things`.
```js
assert.strictEqual(spinalCase('AllThe-small Things'), 'all-the-small-things');

View File

@ -1,6 +1,6 @@
---
id: ab306dbdcc907c7ddfc30830
title: Steamroller
title: Aplanadora
challengeType: 5
forumTopicId: 16079
dashedName: steamroller
@ -8,35 +8,35 @@ dashedName: steamroller
# --description--
Flatten a nested array. You must account for varying levels of nesting.
Aplana un arreglo anidado. Debes tener en cuenta los diferentes niveles de anidación.
# --hints--
`steamrollArray([[["a"]], [["b"]]])` should return `["a", "b"]`.
`steamrollArray([[["a"]], [["b"]]])` debe devolver `["a", "b"]`.
```js
assert.deepEqual(steamrollArray([[['a']], [['b']]]), ['a', 'b']);
```
`steamrollArray([1, [2], [3, [[4]]]])` should return `[1, 2, 3, 4]`.
`steamrollArray([1, [2], [3, [[4]]]])` debe devolver `[1, 2, 3, 4]`.
```js
assert.deepEqual(steamrollArray([1, [2], [3, [[4]]]]), [1, 2, 3, 4]);
```
`steamrollArray([1, [], [3, [[4]]]])` should return `[1, 3, 4]`.
`steamrollArray([1, [], [3, [[4]]]])` debe devolver `[1, 3, 4]`.
```js
assert.deepEqual(steamrollArray([1, [], [3, [[4]]]]), [1, 3, 4]);
```
`steamrollArray([1, {}, [3, [[4]]]])` should return `[1, {}, 3, 4]`.
`steamrollArray([1, {}, [3, [[4]]]])` debe devolver `[1, {}, 3, 4]`.
```js
assert.deepEqual(steamrollArray([1, {}, [3, [[4]]]]), [1, {}, 3, 4]);
```
Your solution should not use the `Array.prototype.flat()` or `Array.prototype.flatMap()` methods.
Tu solución no debe utilizar los métodos `Array.prototype.flat()` o `Array.prototype.flatMap()`.
```js
assert(!code.match(/\.\s*flat\s*\(/) && !code.match(/\.\s*flatMap\s*\(/));

View File

@ -1,6 +1,6 @@
---
id: a3566b1109230028080c9345
title: Sum All Numbers in a Range
title: Suma todos los números en un rango
challengeType: 5
forumTopicId: 16083
dashedName: sum-all-numbers-in-a-range
@ -8,37 +8,37 @@ dashedName: sum-all-numbers-in-a-range
# --description--
We'll pass you an array of two numbers. Return the sum of those two numbers plus the sum of all the numbers between them. The lowest number will not always come first.
Te pasaremos un arreglo de dos números. Devuelve la suma de estos dos números más la suma de todos los números entre ellos. El número más bajo no siempre será el primero.
For example, `sumAll([4,1])` should return `10` because sum of all the numbers between 1 and 4 (both inclusive) is `10`.
Por ejemplo, `sumAll([4,1])`> debe devolver `10` porque la suma de todos los números entre 1 y 4 (ambos incluidos) es `10`.
# --hints--
`sumAll([1, 4])` should return a number.
`sumAll([1, 4])` debe devolver un número.
```js
assert(typeof sumAll([1, 4]) === 'number');
```
`sumAll([1, 4])` should return 10.
`sumAll([1, 4])` debe devolver 10.
```js
assert.deepEqual(sumAll([1, 4]), 10);
```
`sumAll([4, 1])` should return 10.
`sumAll([4, 1])` debe devolver 10.
```js
assert.deepEqual(sumAll([4, 1]), 10);
```
`sumAll([5, 10])` should return 45.
`sumAll([5, 10])` debe devolver 45.
```js
assert.deepEqual(sumAll([5, 10]), 45);
```
`sumAll([10, 5])` should return 45.
`sumAll([10, 5])` debería devolver 45.
```js
assert.deepEqual(sumAll([10, 5]), 45);

View File

@ -1,6 +1,6 @@
---
id: a5229172f011153519423690
title: Sum All Odd Fibonacci Numbers
title: Suma todos los números impares de Fibonacci
challengeType: 5
forumTopicId: 16084
dashedName: sum-all-odd-fibonacci-numbers
@ -8,45 +8,45 @@ dashedName: sum-all-odd-fibonacci-numbers
# --description--
Given a positive integer `num`, return the sum of all odd Fibonacci numbers that are less than or equal to `num`.
Dado un entero positivo `num`, devuelve la suma de todos los números impares de Fibonacci que son menores o iguales a `num`.
The first two numbers in the Fibonacci sequence are 1 and 1. Every additional number in the sequence is the sum of the two previous numbers. The first six numbers of the Fibonacci sequence are 1, 1, 2, 3, 5 and 8.
Los dos primeros números en la secuencia de Fibonacci son 1 y 1. Cada número adicional en la secuencia es la suma de los dos números anteriores. Los seis primeros números de la secuencia de Fibonacci son 1, 1, 2, 3, 5 y 8.
For example, `sumFibs(10)` should return `10` because all odd Fibonacci numbers less than or equal to `10` are 1, 1, 3, and 5.
Por ejemplo, `sumFibs(10)` debe devolver `10` porque todos los números impares de Fibonacci menores o iguales a `10` son 1, 1, 3 y 5.
# --hints--
`sumFibs(1)` should return a number.
`sumFibs(1)` debe devolver un número.
```js
assert(typeof sumFibs(1) === 'number');
```
`sumFibs(1000)` should return 1785.
`sumFibs(1000)` debe devolver 1785.
```js
assert(sumFibs(1000) === 1785);
```
`sumFibs(4000000)` should return 4613732.
`sumFibs(4000000)` debe devolver 4613732.
```js
assert(sumFibs(4000000) === 4613732);
```
`sumFibs(4)` should return 5.
`sumFibs(4)` debe devolver 5.
```js
assert(sumFibs(4) === 5);
```
`sumFibs(75024)` should return 60696.
`sumFibs(75024)` debe devolver 60696.
```js
assert(sumFibs(75024) === 60696);
```
`sumFibs(75025)` should return 135721.
`sumFibs(75025)` debe devolver 135721.
```js
assert(sumFibs(75025) === 135721);

View File

@ -1,6 +1,6 @@
---
id: a3bfc1673c0526e06d3ac698
title: Sum All Primes
title: Suma todos los números primos
challengeType: 5
forumTopicId: 16085
dashedName: sum-all-primes
@ -8,25 +8,25 @@ dashedName: sum-all-primes
# --description--
A <dfn>prime number</dfn> is a whole number greater than 1 with exactly two divisors: 1 and itself. For example, 2 is a prime number because it is only divisible by 1 and 2. In contrast, 4 is not prime since it is divisible by 1, 2 and 4.
Un <dfn>número primo</dfn> es un número entero mayor que 1 con sólo dos divisores: 1 y el propio número. Por ejemplo, 2 es un número primo porque sólo es divisible entre 1 y 2. Por el contrario, 4 no es primo ya que es divisible entre 1, 2 y 4.
Rewrite `sumPrimes` so it returns the sum of all prime numbers that are less than or equal to num.
Reescribe `sumPrimes` para que devuelva la suma de todos los números primos que sean menores o iguales a num.
# --hints--
`sumPrimes(10)` should return a number.
`sumPrimes(10)` debe devolver un número.
```js
assert.deepEqual(typeof sumPrimes(10), 'number');
```
`sumPrimes(10)` should return 17.
`sumPrimes(10)` debe devolver 17.
```js
assert.deepEqual(sumPrimes(10), 17);
```
`sumPrimes(977)` should return 73156.
`sumPrimes(977)` debe devolver 73156.
```js
assert.deepEqual(sumPrimes(977), 73156);