--- id: 587d8249367417b2b2512c42 title: Tracciatore di problemi challengeType: 4 forumTopicId: 301569 dashedName: issue-tracker --- # --description-- Costruisci un'app JavaScript full-stack che sia funzionalmente simile a questa: . Lavorare su questo progetto ti porterà a scrivere il tuo codice utilizzando uno dei seguenti metodi: - Clonare [questo repository GitHub](https://github.com/freeCodeCamp/boilerplate-project-issuetracker/) e completare il tuo progetto localmente. - Usare [la nostra bozza di progetto su Replit](https://replit.com/github/freeCodeCamp/boilerplate-project-issuetracker) per completare il tuo progetto. - Usare un costruttore di siti a tua scelta per completare il progetto. Assicurati di incorporare tutti i file del nostro repository GitHub. 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. ```js (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`. ```js 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`. ```js 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' }` ```js 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. ```js 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. ```js 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 }`. ```js 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' }`. ```js 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 }`. ```js 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 }`. ```js 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. ```js 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-- ```js /** 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. */ ```