13 KiB
id, title, challengeType, forumTopicId, dashedName
id | title | challengeType | forumTopicId | dashedName |
---|---|---|---|---|
587d8249367417b2b2512c42 | Seguidor de incidentes | 4 | 301569 | issue-tracker |
--description--
Construye una aplicación full stack de JavaScript que sea funcionalmente similar a esta: https://issue-tracker.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--
- Completa las rutas necesarias en
/routes/api.js
- Crea todas las siguientes pruebas funcionales en
tests/2_functional-tests.js
- Copia el archivo
sample.env
a.env
y establece las variables apropiadamente - Para ejecutar las pruebas, descomenta
NODE_ENV=test
en tu archivo.env
- Para ejecutar las pruebas en la consola, usa el comando
npm run test
. Para abrir la consola de Replit presiona Ctrl+Shift+P (Cmd si estas en Mac) y escribe "open shell"
Escribe las siguientes pruebas en tests/2_functional-tests.js
:
- Crear un problema con cada campo: solicitud POST a
/api/issues/{project}
- Crear un problema con sólo los campos requeridos: solicitud POST a
/api/issues/{project}
- Crear un problema con los campos requeridos faltantes: solicitud POST a
/api/issues/{project}
- Ver problemas en un proyecto: Solicitud GET a
/api/issues/{project}
- Ver problemas en un proyecto con un filtro: Solicitud GET a
/api/issues/{project}
- Ver problemas en un proyecto con múltiples filtros: Solicitud GET a
/api/issues/{project}
- Actualizar un campo en un problema: Solicitud PUT a
/api/issues/{project}
- Actualizar varios campos en un problema: Solicitud PUT a
/api/issues/{project}
- Actualizar un problema con
_id
faltante: solicitud PUT a/api/issues/{project}
- Actualizar un problema sin campos para actualizar: solicitud PUT a
/api/issues/{project}
- Actualizar un problema con un
_id
inválido: Solicitud PUT a/api/issues/{project}
- Eliminar un problema: solicitud DELETE a
/api/issues/{project}
- Eliminar un problema con un
_id
inválido: solicitud DELETE a/api/issues/{project}
- Eliminar un problema con
_id
faltante: solicitud DELETE a/api/issues/{project}
--hints--
Debes proveer tu propio proyecto, no la URL de ejemplo.
(getUserInput) => {
assert(!/.*\/issue-tracker\.freecodecamp\.rocks/.test(getUserInput('url')));
};
Puedes enviar una solicitud POST
a /api/issues/{projectname}
con datos de formulario que contienen los campos obligatorios issue_title
, issue_text
, created_by
, y opcionalmente assigned_to
y status_text
.
async (getUserInput) => {
try {
let test_data = {
issue_title: 'Faux Issue Title',
issue_text: 'Functional Test - Required Fields Only',
created_by: 'fCC'
};
const data = await $.post(
getUserInput('url') + '/api/issues/fcc-project',
test_data
);
assert.isObject(data);
assert.nestedInclude(data, test_data);
} catch (err) {
throw new Error(err.responseText || err.message);
}
};
La solicitud POST
a /api/issues/{projectname}
devolverá el objeto creado y debe incluir todos los campos enviados. Los campos opcionales excluidos serán devueltos como cadenas vacías. Además, incluye created_on
(fecha/hora), updated_on
(fecha/hora), open
(booleano, true
para abrir - valor predeterminado, false
para cerrar), y _id
.
async (getUserInput) => {
try {
let test_data = {
issue_title: 'Faux Issue Title 2',
issue_text: 'Functional Test - Every field filled in',
created_by: 'fCC',
assigned_to: 'Chai and Mocha'
};
const data = await $.post(
getUserInput('url') + '/api/issues/fcc-project',
test_data
);
assert.isObject(data);
assert.nestedInclude(data, test_data);
assert.property(data, 'created_on');
assert.isNumber(Date.parse(data.created_on));
assert.property(data, 'updated_on');
assert.isNumber(Date.parse(data.updated_on));
assert.property(data, 'open');
assert.isBoolean(data.open);
assert.isTrue(data.open);
assert.property(data, '_id');
assert.isNotEmpty(data._id);
assert.property(data, 'status_text');
assert.isEmpty(data.status_text);
} catch (err) {
throw new Error(err.responseText || err.message);
}
};
Si envías una solicitud POST
a /api/issues/{projectname}
sin los campos requeridos, será devuelto el error { error: 'required field(s) missing' }
async (getUserInput) => {
try {
let test_data = { created_by: 'fCC' };
const data = await $.post(getUserInput('url') + '/api/issues/fcc-project', {
created_by: 'fCC'
});
assert.isObject(data);
assert.property(data, 'error');
assert.equal(data.error, 'required field(s) missing');
} catch (err) {
throw new Error(err.responseText || err.message);
}
};
Puedes enviar una solicitud GET
a /api/issues/{projectname}
para un arreglo de todos los incidentes para ese projectname
, con todos los campos presentes para cada incidente.
async (getUserInput) => {
try {
let test_data = { issue_text: 'Get Issues Test', created_by: 'fCC' };
const url =
getUserInput('url') +
'/api/issues/get_issues_test_' +
Date.now().toString().substring(7);
const data1 = await $.post(
url,
Object.assign(test_data, { issue_title: 'Faux Issue 1' })
);
assert.isObject(data1);
const data2 = await $.post(
url,
Object.assign(test_data, { issue_title: 'Faux Issue 2' })
);
assert.isObject(data2);
const data3 = await $.post(
url,
Object.assign(test_data, { issue_title: 'Faux Issue 3' })
);
assert.isObject(data3);
const getIssues = await $.get(url);
assert.isArray(getIssues);
assert.lengthOf(getIssues, 3);
let re = new RegExp('Faux Issue \\d');
getIssues.forEach((issue) => {
assert.property(issue, 'issue_title');
assert.match(issue.issue_title, re);
assert.property(issue, 'issue_text');
assert.property(issue, 'created_by');
assert.property(issue, 'assigned_to');
assert.property(issue, 'status_text');
assert.property(issue, 'open');
assert.property(issue, 'created_on');
assert.property(issue, 'updated_on');
assert.property(issue, '_id');
});
} catch (err) {
throw new Error(err.responseText || err.message);
}
};
Puedes enviar una solicitud GET
a /api/issues/{projectname}
y filtrar la solicitud también, pasando por cualquier campo y valor como una consulta de URL (por ejemplo, /api/issues/{project}?open=false
). Puedes pasar uno o más pares de campo/valor a la vez.
async (getUserInput) => {
try {
let test_data = {
issue_title: 'To be Filtered',
issue_text: 'Filter Issues Test'
};
const url =
getUserInput('url') +
'/api/issues/get_issues_test_' +
Date.now().toString().substring(7);
const data1 = await $.post(
url,
Object.assign(test_data, { created_by: 'Alice', assigned_to: 'Bob' })
);
const data2 = await $.post(
url,
Object.assign(test_data, { created_by: 'Alice', assigned_to: 'Bob' })
);
const data3 = await $.post(
url,
Object.assign(test_data, { created_by: 'Alice', assigned_to: 'Eric' })
);
const data4 = await $.post(
url,
Object.assign(test_data, { created_by: 'Carol', assigned_to: 'Eric' })
);
const getSingle = await $.get(url + '?created_by=Alice');
assert.isArray(getSingle);
assert.lengthOf(getSingle, 3);
const getMultiple = await $.get(url + '?created_by=Alice&assigned_to=Bob');
assert.isArray(getMultiple);
assert.lengthOf(getMultiple, 2);
} catch (err) {
throw new Error(err.responseText || err.message);
}
};
Puedes enviar una solicitud PUT
a /api/issues/{projectname}
con un _id
y uno o más campos para actualizar. En caso de éxito, el campo updated_on
debe actualizarse, y debe ser devuelto { result: 'successfully updated', '_id': _id }
.
async (getUserInput) => {
try {
let initialData = {
issue_title: 'Issue to be Updated',
issue_text: 'Functional Test - Put target',
created_by: 'fCC'
};
const url = getUserInput('url') + '/api/issues/fcc-project';
const itemToUpdate = await $.post(url, initialData);
const updateSucccess = await $.ajax({
url: url,
type: 'PUT',
data: { _id: itemToUpdate._id, issue_text: 'New Issue Text' }
});
assert.isObject(updateSucccess);
assert.deepEqual(updateSucccess, {
result: 'successfully updated',
_id: itemToUpdate._id
});
const getUpdatedId = await $.get(url + '?_id=' + itemToUpdate._id);
assert.isArray(getUpdatedId);
assert.isObject(getUpdatedId[0]);
assert.isAbove(
Date.parse(getUpdatedId[0].updated_on),
Date.parse(getUpdatedId[0].created_on)
);
} catch (err) {
throw new Error(err.responseText || err.message);
}
};
Cuando la solicitud PUT
enviada a /api/issues/{projectname}
no incluya un _id
, el valor devuelto es { error: 'missing _id' }
.
async (getUserInput) => {
try {
const url = getUserInput('url') + '/api/issues/fcc-project';
const badUpdate = await $.ajax({ url: url, type: 'PUT' });
assert.isObject(badUpdate);
assert.property(badUpdate, 'error');
assert.equal(badUpdate.error, 'missing _id');
} catch (err) {
throw new Error(err.responseText || err.message);
}
};
Cuando la solicitud PUT
enviada a /api/issues/{projectname}
no incluya los campos para actualizar, el valor devuelto es { error: 'no update field(s) sent', '_id': _id }
. En cualquier otro error, el valor devuelto es { error: 'could not update', '_id': _id }
.
async (getUserInput) => {
try {
const url = getUserInput('url') + '/api/issues/fcc-project';
const badUpdate = await $.ajax({
url: url,
type: 'PUT',
data: { _id: '5f665eb46e296f6b9b6a504d' }
});
assert.deepEqual(badUpdate, {
error: 'no update field(s) sent',
_id: '5f665eb46e296f6b9b6a504d'
});
const badIdUpdate = await $.ajax({
url: url,
type: 'PUT',
data: { _id: '5f665eb46e296f6b9b6a504d', issue_text: 'New Issue Text' }
});
assert.deepEqual(badIdUpdate, {
error: 'could not update',
_id: '5f665eb46e296f6b9b6a504d'
});
} catch (err) {
throw new Error(err.responseText || err.message);
}
};
Puede enviar una solicitud DELETE
a /api/issues/{projectname}
con un _id
para eliminar un problema. Si ningún _id
es enviado, el valor devuelto es { error: 'missing _id' }
. En caso de éxito, el valor devuelto es { result: 'successfully deleted', '_id': _id }
. En caso de fallo, el valor devuelto es { error: 'could not delete', '_id': _id }
.
async (getUserInput) => {
try {
let initialData = {
issue_title: 'Issue to be Deleted',
issue_text: 'Functional Test - Delete target',
created_by: 'fCC'
};
const url = getUserInput('url') + '/api/issues/fcc-project';
const itemToDelete = await $.post(url, initialData);
assert.isObject(itemToDelete);
const deleteSuccess = await $.ajax({
url: url,
type: 'DELETE',
data: { _id: itemToDelete._id }
});
assert.isObject(deleteSuccess);
assert.deepEqual(deleteSuccess, {
result: 'successfully deleted',
_id: itemToDelete._id
});
const noId = await $.ajax({ url: url, type: 'DELETE' });
assert.isObject(noId);
assert.deepEqual(noId, { error: 'missing _id' });
const badIdDelete = await $.ajax({
url: url,
type: 'DELETE',
data: { _id: '5f665eb46e296f6b9b6a504d', issue_text: 'New Issue Text' }
});
assert.isObject(badIdDelete);
assert.deepEqual(badIdDelete, {
error: 'could not delete',
_id: '5f665eb46e296f6b9b6a504d'
});
} catch (err) {
throw new Error(err.responseText || err.message);
}
};
Las 14 pruebas funcionales están completas y pasan.
async (getUserInput) => {
try {
const getTests = await $.get(getUserInput('url') + '/_api/get-tests');
assert.isArray(getTests);
assert.isAtLeast(getTests.length, 14, 'At least 14 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.
*/