├── .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 |
3 |
4 |
5 |
6 |
7 |
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 |
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 |
--------------------------------------------------------------------------------