8.3 KiB
id, title, challengeType, forumTopicId, dashedName
id | title | challengeType | forumTopicId | dashedName |
---|---|---|---|---|
587d824a367417b2b2512c43 | Biblioteca personal | 4 | 301571 | personal-library |
--description--
Construye una aplicación full stack de JavaScript que sea funcionalmente similar a esta: https://personal-library.freecodecamp.rocks/. Trabajar en este proyecto implicará escribir tu código utilizando uno de los siguientes métodos:
- Clona este repositorio de GitHub y completa tu proyecto localmente.
- Usa nuestro proyecto inicial de Replit para completar tu proyecto.
- Usa un constructor de sitios de tu elección para completar el proyecto. Asegúrate de incorporar todos los archivos de nuestro repositorio de GitHub.
Cuando hayas terminado, asegúrate de que una demostración funcional de tu proyecto esté alojado en algún lugar público. Luego, envía la URL en el campo Solution Link
. Opcionalmente, también envía un enlace al código fuente de tu proyecto en el campo GitHub Link
.
--instructions--
- Agrega tu cadena de conexión MongoDB a tu
.env
sin comillas comoDB
Ejemplo:DB=mongodb://admin:pass@1234.mlab.com:1234/fccpersonallib
- En tu archivo
.env
estableceNODE_ENV
atest
, sin comillas - Es necesario crear todas la rutas dentro de
routes/api.js
- Escribe las siguientes pruebas en
tests/2_functional-tests.js
--hints--
Debes proporcionar tu propio proyecto, no la URL de ejemplo.
(getUserInput) => {
assert(
!/.*\/personal-library\.freecodecamp\.rocks/.test(getUserInput('url'))
);
};
Puedes enviar una petición POST a /api/books
con title
como parte de los datos del formulario para agregar un libro. La respuesta devuelta será un objeto con las propiedades title
y un _id
único como claves. Si title
no está incluido en la petición, la respuesta devuelta será una cadena con 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);
}
};
Puedes enviar una petición GET a /api/books
y recibir una respuesta JSON que representa todos los libros. La respuesta JSON será un arreglo de objetos, cada objeto (libro) contienen las propiedades de title
, _id
, y 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);
}
};
Puedes enviar una petición GET a /api/books/{_id}
para recuperar un solo objeto de un libro que contiene las propiedades title
, _id
, y un arreglo comments
(arreglo vacío si no hay comentarios). Si no se encuentra ningún libro, devuelve la cadena 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);
}
};
Puedes enviar una petición de POST que contenga un comment
como los datos del cuerpo del formulario a /api/books/{_id}
para agregar un comentario a un libro. La respuesta devuelta será el objeto de libros similar a la petición GET /api/books/{_id}
en una prueba anterior. Si comment
no está incluido en la petición, la respuesta devuelta será una cadena con missing required field comment
. Si no se encuentra ningún libro, devuelve la cadena 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);
}
};
Puedes enviar una petición de DELETE a /api/books/{_id}
para eliminar un libro de la colección. La respuesta devuelta será la cadena delete successful
si tiene éxito. Si no se encuentra ningún libro, devuelve la cadena 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);
}
};
Puedes enviar una petición de DELETE a /api/books
para eliminar todos los libros de la base de datos. La respuesta devuelta será la cadena 'complete delete successful
si tiene éxito.
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);
}
};
Las 10 pruebas funcionales requeridas están completas y aprobadas.
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.
*/