7.9 KiB
id, title, challengeType, forumTopicId, dashedName
id | title | challengeType | forumTopicId | dashedName |
---|---|---|---|---|
587d824a367417b2b2512c43 | 個人圖書館 | 4 | 301571 | personal-library |
--description--
構建一個 JavaScript 的全棧應用,在功能上與這個應用相似:https://personal-library.freecodecamp.rocks/。 可以採用下面的任意一種方式完成這個挑戰:
- 克隆 這個 GitHub 倉庫 並在本地完成項目。
- 使用我們的 Replit 初始化項目來完成你的項目。
- 使用一個你喜歡的站點生成器來完成項目。 需要確定包含了我們 GitHub 倉庫的所有文件。
完成本項目後,請將一個正常運行的 demo(項目演示)託管在可以公開訪問的平臺。 然後在 Solution Link
框中提交你的項目 URL。 此外,還可以將項目的源碼提交到 GitHub Link
中。
--instructions--
- 將你的 MongoDB 連接字符串添加到
.env
中,作爲DB
示例:DB=mongodb://admin:pass@1234.mlab.com:1234/fccpersonallib
- 在
.env
文件中設置NODE_ENV
爲test
中,沒有引號 - 需要在
routes/api.js
中創建所有路由 - 在
tests/2_functional-tests.js
中創建所有的功能測試
--hints--
提交自己的項目,而不是示例的 URL。
(getUserInput) => {
assert(
!/.*\/personal-library\.freecodecamp\.rocks/.test(getUserInput('url'))
);
};
可以發送 POST 請求到 /api/books
,帶有 title
作爲表單數據的一部分,來添加一本書。 返回的響應將是一個包含 title
和唯一的 _id
作爲鍵的對象。 如果 title
未包含在請求中,返回的響應應該是字符串 missing required field title
。
async (getUserInput) => {
try {
let data1 = await $.post(getUserInput('url') + '/api/books', {
title: 'Faux Book 1'
});
assert.isObject(data1);
assert.property(data1, 'title');
assert.equal(data1.title, 'Faux Book 1');
assert.property(data1, '_id');
let data2 = await $.post(getUserInput('url') + '/api/books');
assert.isString(data2);
assert.equal(data2, 'missing required field title');
} catch (err) {
throw new Error(err.responseText || err.message);
}
};
可以向 /api/books
發送 GET 請求,並返回代表所有書的 JSON 響應。 JSON 響應應該是一個包含有 title
、_id
和 commentcount
屬性的對象數組 。
async (getUserInput) => {
try {
let url = getUserInput('url') + '/api/books';
let a = $.post(url, { title: 'Faux Book A' });
let b = $.post(url, { title: 'Faux Book B' });
let c = $.post(url, { title: 'Faux Book C' });
await Promise.all([a, b, c]).then(async () => {
let data = await $.get(url);
assert.isArray(data);
assert.isAtLeast(data.length, 3);
data.forEach((book) => {
assert.isObject(book);
assert.property(book, 'title');
assert.isString(book.title);
assert.property(book, '_id');
assert.property(book, 'commentcount');
assert.isNumber(book.commentcount);
});
});
} catch (err) {
throw new Error(err.responseText || err.message);
}
};
可以發送 GET 請求到 /api/books/{_id}
來檢索一本書的單個對象,返回屬性 title
、_id
和 comments
數組 (如果沒有評論,則展示空數組)。 如果找不到書, 返回字符串 no book exists
。
async (getUserInput) => {
try {
let url = getUserInput('url') + '/api/books';
let noBook = await $.get(url + '/5f665eb46e296f6b9b6a504d');
assert.isString(noBook);
assert.equal(noBook, 'no book exists');
let sampleBook = await $.post(url, { title: 'Faux Book Alpha' });
assert.isObject(sampleBook);
let bookId = sampleBook._id;
let bookQuery = await $.get(url + '/' + bookId);
assert.isObject(bookQuery);
assert.property(bookQuery, 'title');
assert.equal(bookQuery.title, 'Faux Book Alpha');
assert.property(bookQuery, 'comments');
assert.isArray(bookQuery.comments);
} catch (err) {
throw new Error(err.responseText || err.message);
}
};
可以發送一個 POST 請求,其中包含 comment
作爲表單正文數據,請求到 /api/books/{_id}
以便將評論添加到書中。 返回的響應將是書對象,在先前測試中 GET /api/books/{_id}
類似。 如果請求中沒有包含 comment
,返回字符串 missing required field comment
。 如果找不到書, 返回字符串 no book exists
。
async (getUserInput) => {
try {
let url = getUserInput('url') + '/api/books';
let commentTarget = await $.post(url, { title: 'Notable Book' });
assert.isObject(commentTarget);
let bookId = commentTarget._id;
let bookCom1 = await $.post(url + '/' + bookId, {
comment: 'This book is fab!'
});
let bookCom2 = await $.post(url + '/' + bookId, {
comment: 'I did not care for it'
});
assert.isObject(bookCom2);
assert.property(bookCom2, '_id');
assert.property(bookCom2, 'title');
assert.property(bookCom2, 'comments');
assert.lengthOf(bookCom2.comments, 2);
bookCom2.comments.forEach((comment) => {
assert.isString(comment);
assert.oneOf(comment, ['This book is fab!', 'I did not care for it']);
});
let commentErr = await $.post(url + '/' + bookId);
assert.isString(commentErr);
assert.equal(commentErr, 'missing required field comment');
let failingComment = await $.post(url + '/5f665eb46e296f6b9b6a504d', {
comment: 'Never Seen Comment'
});
assert.isString(failingComment);
assert.equal(failingComment, 'no book exists');
} catch (err) {
throw new Error(err.responseText || err.message);
}
};
可以向 /api/books/{_id}
發送 DELETE 請求,從收藏中刪除一本書。 如果成功,返回的響應將是字符串 delete successful
。 如果找不到書, 返回字符串 no book exists
。
async (getUserInput) => {
try {
let url = getUserInput('url') + '/api/books';
let deleteTarget = await $.post(url, { title: 'Deletable Book' });
assert.isObject(deleteTarget);
let bookId = deleteTarget._id;
let doDelete = await $.ajax({ url: url + '/' + bookId, type: 'DELETE' });
assert.isString(doDelete);
assert.equal(doDelete, 'delete successful');
let failingDelete = await $.ajax({
url: url + '/5f665eb46e296f6b9b6a504d',
type: 'DELETE'
});
assert.isString(failingDelete);
assert.equal(failingDelete, 'no book exists');
} catch (err) {
throw new Error(err.responseText || err.message);
}
};
可以向 /api/books
發送 DELETE 請求來刪除數據庫中的所有書籍。 如果成功,返回的響應將是字符串 'complete delete successful
。
async (getUserInput) => {
try {
const deleteAll = await $.ajax({
url: getUserInput('url') + '/api/books',
type: 'DELETE'
});
assert.isString(deleteAll);
assert.equal(deleteAll, 'complete delete successful');
} catch (err) {
throw new Error(err.responseText || err.message);
}
};
所有 10 項功能測試都已完成並通過。
async (getUserInput) => {
try {
const getTests = await $.get(getUserInput('url') + '/_api/get-tests');
assert.isArray(getTests);
assert.isAtLeast(getTests.length, 10, 'At least 10 tests passed');
getTests.forEach((test) => {
assert.equal(test.state, 'passed', 'Test in Passed State');
assert.isAtLeast(
test.assertions.length,
1,
'At least one assertion per test'
);
});
} catch (err) {
throw new Error(err.responseText || err.message);
}
};
--solutions--
/**
Backend challenges don't need solutions,
because they would need to be tested against a full working project.
Please check our contributing guidelines to learn more.
*/