Files
2022-02-20 07:36:06 -08:00

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:

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 _idfaltante: 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.
*/