├── .gitignore ├── README.md ├── jest.config.js ├── nodemon.json ├── package.json └── src ├── __tests__ ├── likes.spec.js └── repositories.spec.js ├── app.js └── server.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | Rocketseat Education 3 |

4 | 5 |

6 | Rocketseat Project 7 | License 8 |

9 | 10 | 11 | ## 💻 Projeto 12 | 13 | gostack-template-conceitos-nodejs 14 | 15 | ## 📝 Licença 16 | 17 | Esse projeto está sob a licença MIT. Veja o arquivo [LICENSE](LICENSE) para mais detalhes. 18 | 19 | --- 20 | 21 |

22 | Feito com 💜 by Rocketseat 23 |

24 | 25 | 26 | 27 | 28 |
29 |
30 | 31 |

32 | 33 | banner 34 | 35 |

36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | // For a detailed explanation regarding each configuration property, visit: 2 | // https://jestjs.io/docs/en/configuration.html 3 | 4 | module.exports = { 5 | // All imported modules in your tests should be mocked automatically 6 | // automock: false, 7 | 8 | // Stop running tests after `n` failures 9 | // bail: 0, 10 | 11 | // Respect "browser" field in package.json when resolving modules 12 | // browser: false, 13 | 14 | // The directory where Jest should store its cached dependency information 15 | // cacheDirectory: "/private/var/folders/qv/s8ph22xx2fnfxdh3pq14t4d40000gn/T/jest_dx", 16 | 17 | // Automatically clear mock calls and instances between every test 18 | clearMocks: true, 19 | 20 | // Indicates whether the coverage information should be collected while executing the test 21 | // collectCoverage: false, 22 | 23 | // An array of glob patterns indicating a set of files for which coverage information should be collected 24 | // collectCoverageFrom: undefined, 25 | 26 | // The directory where Jest should output its coverage files 27 | // coverageDirectory: "coverage", 28 | 29 | // An array of regexp pattern strings used to skip coverage collection 30 | // coveragePathIgnorePatterns: [ 31 | // "/node_modules/" 32 | // ], 33 | 34 | // A list of reporter names that Jest uses when writing coverage reports 35 | // coverageReporters: [ 36 | // "json", 37 | // "text", 38 | // "lcov", 39 | // "clover" 40 | // ], 41 | 42 | // An object that configures minimum threshold enforcement for coverage results 43 | // coverageThreshold: undefined, 44 | 45 | // A path to a custom dependency extractor 46 | // dependencyExtractor: undefined, 47 | 48 | // Make calling deprecated APIs throw helpful error messages 49 | // errorOnDeprecated: false, 50 | 51 | // Force coverage collection from ignored files using an array of glob patterns 52 | // forceCoverageMatch: [], 53 | 54 | // A path to a module which exports an async function that is triggered once before all test suites 55 | // globalSetup: undefined, 56 | 57 | // A path to a module which exports an async function that is triggered once after all test suites 58 | // globalTeardown: undefined, 59 | 60 | // A set of global variables that need to be available in all test environments 61 | // globals: {}, 62 | 63 | // The maximum amount of workers used to run your tests. Can be specified as % or a number. E.g. maxWorkers: 10% will use 10% of your CPU amount + 1 as the maximum worker number. maxWorkers: 2 will use a maximum of 2 workers. 64 | // maxWorkers: "50%", 65 | 66 | // An array of directory names to be searched recursively up from the requiring module's location 67 | // moduleDirectories: [ 68 | // "node_modules" 69 | // ], 70 | 71 | // An array of file extensions your modules use 72 | // moduleFileExtensions: [ 73 | // "js", 74 | // "json", 75 | // "jsx", 76 | // "ts", 77 | // "tsx", 78 | // "node" 79 | // ], 80 | 81 | // A map from regular expressions to module names or to arrays of module names that allow to stub out resources with a single module 82 | // moduleNameMapper: {}, 83 | 84 | // An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader 85 | // modulePathIgnorePatterns: [], 86 | 87 | // Activates notifications for test results 88 | // notify: false, 89 | 90 | // An enum that specifies notification mode. Requires { notify: true } 91 | // notifyMode: "failure-change", 92 | 93 | // A preset that is used as a base for Jest's configuration 94 | // preset: undefined, 95 | 96 | // Run tests from one or more projects 97 | // projects: undefined, 98 | 99 | // Use this configuration option to add custom reporters to Jest 100 | // reporters: undefined, 101 | 102 | // Automatically reset mock state between every test 103 | // resetMocks: false, 104 | 105 | // Reset the module registry before running each individual test 106 | // resetModules: false, 107 | 108 | // A path to a custom resolver 109 | // resolver: undefined, 110 | 111 | // Automatically restore mock state between every test 112 | // restoreMocks: false, 113 | 114 | // The root directory that Jest should scan for tests and modules within 115 | // rootDir: undefined, 116 | 117 | // A list of paths to directories that Jest should use to search for files in 118 | // roots: [ 119 | // "" 120 | // ], 121 | 122 | // Allows you to use a custom runner instead of Jest's default test runner 123 | // runner: "jest-runner", 124 | 125 | // The paths to modules that run some code to configure or set up the testing environment before each test 126 | // setupFiles: [], 127 | 128 | // A list of paths to modules that run some code to configure or set up the testing framework before each test 129 | // setupFilesAfterEnv: [], 130 | 131 | // A list of paths to snapshot serializer modules Jest should use for snapshot testing 132 | // snapshotSerializers: [], 133 | 134 | // The test environment that will be used for testing 135 | testEnvironment: "node", 136 | 137 | // Options that will be passed to the testEnvironment 138 | // testEnvironmentOptions: {}, 139 | 140 | // Adds a location field to test results 141 | // testLocationInResults: false, 142 | 143 | // The glob patterns Jest uses to detect test files 144 | // testMatch: [ 145 | // "**/__tests__/**/*.[jt]s?(x)", 146 | // "**/?(*.)+(spec|test).[tj]s?(x)" 147 | // ], 148 | 149 | // An array of regexp pattern strings that are matched against all test paths, matched tests are skipped 150 | // testPathIgnorePatterns: [ 151 | // "/node_modules/" 152 | // ], 153 | 154 | // The regexp pattern or array of patterns that Jest uses to detect test files 155 | // testRegex: [], 156 | 157 | // This option allows the use of a custom results processor 158 | // testResultsProcessor: undefined, 159 | 160 | // This option allows use of a custom test runner 161 | // testRunner: "jasmine2", 162 | 163 | // This option sets the URL for the jsdom environment. It is reflected in properties such as location.href 164 | // testURL: "http://localhost", 165 | 166 | // Setting this value to "fake" allows the use of fake timers for functions such as "setTimeout" 167 | // timers: "real", 168 | 169 | // A map from regular expressions to paths to transformers 170 | // transform: undefined, 171 | 172 | // An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation 173 | // transformIgnorePatterns: [ 174 | // "/node_modules/" 175 | // ], 176 | 177 | // An array of regexp pattern strings that are matched against all modules before the module loader will automatically return a mock for them 178 | // unmockedModulePathPatterns: undefined, 179 | 180 | // Indicates whether each individual test should be reported during the run 181 | // verbose: undefined, 182 | 183 | // An array of regexp patterns that are matched against all source file paths before re-running tests in watch mode 184 | // watchPathIgnorePatterns: [], 185 | 186 | // Whether to use watchman for file crawling 187 | // watchman: true, 188 | testTimeout: 500 189 | }; 190 | -------------------------------------------------------------------------------- /nodemon.json: -------------------------------------------------------------------------------- 1 | { 2 | "ignore": ["__tests__"] 3 | } 4 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "backend", 3 | "version": "1.0.0", 4 | "main": "src/server.js", 5 | "license": "MIT", 6 | "scripts": { 7 | "dev": "nodemon", 8 | "test": "jest" 9 | }, 10 | "dependencies": { 11 | "cors": "^2.8.5", 12 | "express": "^4.17.1", 13 | "uuid": "^8.3.0" 14 | }, 15 | "devDependencies": { 16 | "jest": "^25.2.6", 17 | "nodemon": "^2.0.2", 18 | "supertest": "^4.0.2" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/__tests__/likes.spec.js: -------------------------------------------------------------------------------- 1 | const request = require("supertest"); 2 | const app = require("../app"); 3 | 4 | describe("Likes", () => { 5 | it("should be able to give a like to the repository", async () => { 6 | const repository = await request(app) 7 | .post("/repositories") 8 | .send({ 9 | url: "https://github.com/Rocketseat/umbriel", 10 | title: "Umbriel", 11 | techs: ["Node", "Express", "TypeScript"] 12 | }); 13 | 14 | let response = await request(app).post( 15 | `/repositories/${repository.body.id}/like` 16 | ); 17 | 18 | expect(response.body).toMatchObject({ 19 | likes: 1 20 | }); 21 | 22 | response = await request(app).post( 23 | `/repositories/${repository.body.id}/like` 24 | ); 25 | 26 | expect(response.body).toMatchObject({ 27 | likes: 2 28 | }); 29 | }); 30 | 31 | it("should not be able to like a repository that does not exist", async () => { 32 | await request(app) 33 | .post(`/repositories/123/like`) 34 | .expect(400); 35 | }); 36 | }); 37 | -------------------------------------------------------------------------------- /src/__tests__/repositories.spec.js: -------------------------------------------------------------------------------- 1 | const request = require("supertest"); 2 | const app = require("../app"); 3 | const { validate: isUuid } = require("uuid"); 4 | 5 | describe("Repositories", () => { 6 | it("should be able to create a new repository", async () => { 7 | const response = await request(app) 8 | .post("/repositories") 9 | .send({ 10 | url: "https://github.com/Rocketseat/umbriel", 11 | title: "Umbriel", 12 | techs: ["Node", "Express", "TypeScript"] 13 | }); 14 | 15 | expect(isUuid(response.body.id)).toBe(true); 16 | 17 | expect(response.body).toMatchObject({ 18 | url: "https://github.com/Rocketseat/umbriel", 19 | title: "Umbriel", 20 | techs: ["Node", "Express", "TypeScript"], 21 | likes: 0 22 | }); 23 | }); 24 | 25 | it("should be able to list the repositories", async () => { 26 | const repository = await request(app) 27 | .post("/repositories") 28 | .send({ 29 | url: "https://github.com/Rocketseat/umbriel", 30 | title: "Umbriel", 31 | techs: ["Node", "Express", "TypeScript"] 32 | }); 33 | 34 | const response = await request(app).get("/repositories"); 35 | 36 | expect(response.body).toEqual( 37 | expect.arrayContaining([ 38 | { 39 | id: repository.body.id, 40 | url: "https://github.com/Rocketseat/umbriel", 41 | title: "Umbriel", 42 | techs: ["Node", "Express", "TypeScript"], 43 | likes: 0 44 | } 45 | ]) 46 | ); 47 | }); 48 | 49 | it("should be able to update repository", async () => { 50 | const repository = await request(app) 51 | .post("/repositories") 52 | .send({ 53 | url: "https://github.com/Rocketseat/umbriel", 54 | title: "Umbriel", 55 | techs: ["Node", "Express", "TypeScript"] 56 | }); 57 | 58 | const response = await request(app) 59 | .put(`/repositories/${repository.body.id}`) 60 | .send({ 61 | url: "https://github.com/Rocketseat/unform", 62 | title: "Unform", 63 | techs: ["React", "ReactNative", "TypeScript", "ContextApi"] 64 | }); 65 | 66 | expect(isUuid(response.body.id)).toBe(true); 67 | 68 | expect(response.body).toMatchObject({ 69 | url: "https://github.com/Rocketseat/unform", 70 | title: "Unform", 71 | techs: ["React", "ReactNative", "TypeScript", "ContextApi"] 72 | }); 73 | }); 74 | 75 | it("should not be able to update a repository that does not exist", async () => { 76 | await request(app).put(`/repositories/123`).expect(400); 77 | }); 78 | 79 | it("should not be able to update repository likes manually", async () => { 80 | const repository = await request(app) 81 | .post("/repositories") 82 | .send({ 83 | url: "https://github.com/Rocketseat/umbriel", 84 | title: "Umbriel", 85 | techs: ["React", "ReactNative", "TypeScript", "ContextApi"] 86 | }); 87 | 88 | await request(app) 89 | .post(`/repositories/${repository.body.id}/like`); 90 | 91 | const response = await request(app) 92 | .put(`/repositories/${repository.body.id}`) 93 | .send({ 94 | likes: 15 95 | }); 96 | 97 | expect(response.body).toMatchObject({ 98 | likes: 1 99 | }); 100 | }); 101 | 102 | it("should be able to delete the repository", async () => { 103 | const response = await request(app) 104 | .post("/repositories") 105 | .send({ 106 | url: "https://github.com/Rocketseat/umbriel", 107 | title: "Umbriel", 108 | techs: ["Node", "Express", "TypeScript"] 109 | }); 110 | 111 | await request(app).delete(`/repositories/${response.body.id}`).expect(204); 112 | 113 | const repositories = await request(app).get("/repositories"); 114 | 115 | const repository = repositories.body.find((r) => r.id === response.body.id); 116 | 117 | expect(repository).toBe(undefined); 118 | }); 119 | 120 | it("should not be able to delete a repository that does not exist", async () => { 121 | await request(app).delete(`/repositories/123`).expect(400); 122 | }); 123 | }); 124 | -------------------------------------------------------------------------------- /src/app.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | const cors = require("cors"); 3 | 4 | // const { v4: uuid, validate: isUuid } = require('uuid'); 5 | 6 | const app = express(); 7 | 8 | app.use(express.json()); 9 | app.use(cors()); 10 | 11 | const repositories = []; 12 | 13 | app.get("/repositories", (request, response) => { 14 | // TODO 15 | }); 16 | 17 | app.post("/repositories", (request, response) => { 18 | // TODO 19 | }); 20 | 21 | app.put("/repositories/:id", (request, response) => { 22 | // TODO 23 | }); 24 | 25 | app.delete("/repositories/:id", (request, response) => { 26 | // TODO 27 | }); 28 | 29 | app.post("/repositories/:id/like", (request, response) => { 30 | // TODO 31 | }); 32 | 33 | module.exports = app; 34 | -------------------------------------------------------------------------------- /src/server.js: -------------------------------------------------------------------------------- 1 | const app = require("./app"); 2 | 3 | app.listen(3333); 4 | --------------------------------------------------------------------------------