Files
freeCodeCamp/curriculum/challenges/italian/06-quality-assurance/quality-assurance-projects/issue-tracker.md

13 KiB

id, title, challengeType, forumTopicId, dashedName
id title challengeType forumTopicId dashedName
587d8249367417b2b2512c42 Tracciatore di problemi 4 301569 issue-tracker

--description--

Costruisci un'app JavaScript full-stack che sia funzionalmente simile a questa: https://issue-tracker.freecodecamp.rocks/. Lavorare su questo progetto ti porterà a scrivere il tuo codice utilizzando uno dei seguenti metodi:

Quando hai finito, assicurati che una demo funzionante del tuo progetto sia ospitata in qualche percorso pubblico. Quindi invia l'URL nel campo Solution Link. Facoltativamente, invia anche un link al codice sorgente del tuo progetto nel campo GitHub Link.

--instructions--

  • Completa le rotte necessarie in /routes/api.js
  • Crea tutti i test funzionali in tests/2_functional-tests.js
  • Copia il file sample.env su .env e imposta le variabili in modo appropriato
  • Per eseguire i test togli i commenti dalla riga NODE_ENV=test nel tuo file .env
  • Per eseguire i test nella console, utilizza il comando npm run test. Per aprire la console di Replit, premi Ctrl+Maiusc+P (Cmd se su un Mac) e digita "open shell"

Scrivi i seguenti test in tests/2_functional-tests.js:

  • Crea un'issue con ogni campo: richiesta POST a /api/issues/{project}
  • Crea un'issue con soli campi obbligatori: richiesta POST a /api/issues/{project}
  • Crea un'issue con i campi obbligatori mancanti: richiesta POST a /api/issues/{project}
  • Visualizza i gli issue di un progetto: richiesta GET a /api/issues/{project}
  • Visualizza gli issue di un progetto con un filtro: richiesta GET a /api/issues/{project}
  • Visualizza gli issue di un progetto con più filtri: richiesta GET a /api/issues/{project}
  • Aggiorna un campo in un issue: richiesta PUT a /api/issues/{project}
  • Aggiorna più campi in un issue: richiesta PUT a /api/issues/{project}
  • Aggiorna un issue con _id mancante: richiesta PUT a /api/issues/{project}
  • Aggiorna un issue che non ha campi da aggiornare: richiesta PUT a /api/issues/{project}
  • Aggiorna un issue con _id invalido: richiesta PUT a /api/issues/{project}
  • Elimina un issue: richiesta DELETE a /api/issues/{project}
  • Elimina un issue con _id invalido: richiesta DELETE a /api/issues/{project}
  • Elimina un issue con _id mancante: richiesta DELETE a /api/issues/{project}

--hints--

È necessario fornire il proprio progetto, non l'URL di esempio.

(getUserInput) => {
  assert(!/.*\/issue-tracker\.freecodecamp\.rocks/.test(getUserInput('url')));
};

Puoi inviare una richiesta POST a /api/issues/{projectname} con i dati del modulo contenenti i campi obbligatori issue_title, issue_text, created_by, e opzionalmente assigned_to e 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 richiesta POST a /api/issues/{projectname} restituirà l'oggetto creato, e deve includere tutti i campi inviati. I campi opzionali esclusi saranno restituiti come stringhe vuote. Inoltre, includi created_on (data/ora), updated_on (data/ora), open (booleano, true per open - valore predefinito, false per chiuso), e _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);
  }
};

Se invii una richiesta POST a /api/issues/{projectname} senza i campi richiesti, deve essere restituito un errore { 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);
  }
};

È possibile inviare una richiesta GET a /api/issues/{projectname} per un array di tutti gli issue per quel specifico projectname, con tutti i campi presenti per ogni issue.

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);
  }
};

Puoi inviare una richiesta GET a /api/issues/{projectname} e filtrare la richiesta passando anche qualsiasi campo e valore come una query di URL (es. /api/issues/{project}?open=false). È possibile passare una o più coppie di campo/valore contemporaneamente.

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);
  }
};

Puoi inviare una richiesta PUT a /api/issues/{projectname} con un _id e uno o più campi da aggiornare. Al successo, il campo updated_on dovrebbe essere aggiornato, e dovrebbe essere restituito { 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);
  }
};

Quando la richiesta PUT inviata a /api/issues/{projectname} non include un _id, deve essere restuito { 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);
  }
};

Quando la richiesta PUT inviata a /api/issues/{projectname} non include campi da aggiornare, deve essere restuito { error: 'no update field(s) sent', '_id': _id }. Su qualsiasi altro errore, il valore restituito deve essere { 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);
  }
};

Puoi inviare una richiesta DELETE a /api/issues/{projectname} con un _id per eliminare un issue. Se non viene inviato un _id , deve essere restuito { error: 'missing _id' }. Al successo, deve essere restituito { result: 'successfully deleted', '_id': _id }. Al fallimento, il valore restituito deve essere { 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);
  }
};

Tutti i 14 test funzionali sono completi e passano.

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