eletrotupi / tcc/ commit / 1d10886

api/tests: fix ava loading paths & add/rework user specs

Pedro Lucas Porcellis porcellis@eletrotupi.com · 6 months ago 1d108862effda2b34ab10ccce2ba8799782afec0 Browse files
Parents ad58511
Changed files
7
Additions
+365
Deletions
-17
api/ava.config.mjs modified+8 -17
api/ava.config.mjs
1 1
export default {
2 -
  "typescript": {
3 -
    "extensions": [
4 -
      "ts",
5 -
      "tsx"
6 -
    ],
7 -
    "rewritePaths": {
8 -
      "src/": "dist/"
9 -
    },
10 -
    compile: false
2 +
  extensions: {
3 +
    ts: 'commonjs'
11 4
  },
12 -
 // extensions: {
13 -
 //   ts: 'module'
14 -
 // },
15 -
 // nodeArguments: [
16 -
 //   '--import=tsx'
17 -
 // ],
5 +
  nodeArguments: [
6 +
    '--require=tsx/cjs',
7 +
    '--require=tsconfig-paths/register'
8 +
  ],
18 9
  files: [
19 10
    'tests/**/*.test.ts'
20 11
  ],
21 12
  environmentVariables: {
22 -
    NODE_ENV: 'test'
13 +
    NODE_ENV: 'test',
14 +
    TS_NODE_PROJECT: './tsconfig.json'
23 15
  },
24 16
  timeout: '30s',
25 17
  concurrency: 1, // Run tests serially to avoid database conflicts
26 18
  verbose: true
27 -
};
19 +
};
api/tests/database-auth.test.ts
1 1
import test from "ava";
2 2
import { PrismaClient } from '@prisma/client';
3 3
import { PrismaPg } from '@prisma/adapter-pg';
4 4
import bcrypt from 'bcryptjs';
5 5
import 'dotenv/config';
22 22
    console.error('Error cleaning test DB:', err);
23 23
  }
24 24
});
25 25

26 26
test.after.always(async () => {
27 +
  const deleteUsers = prisma.user.deleteMany();
28 +

29 +
  await prisma.$transaction([
30 +
    deleteUsers
31 +
  ])
32 +

27 33
  await prisma?.$disconnect();
28 34
});
29 35

30 36
// Basic database connectivity test
31 37
test("database connection works", async (t) => {
250 256
  t.deepEqual(updatedUser.createdAt, user.createdAt);
251 257
  t.true(updatedUser.updatedAt >= beforeUpdate);
252 258
  t.true(updatedUser.updatedAt <= afterUpdate);
253 259
  t.true(updatedUser.updatedAt > user.updatedAt);
254 260
});
/dev/null → api/tests/users/create.test.ts
1 +
import test from "ava";
2 +
import { PrismaClient } from '@prisma/client';
3 +
import { PrismaPg } from '@prisma/adapter-pg';
4 +
import request from 'supertest';
5 +
import jwt from 'jsonwebtoken';
6 +
import 'dotenv/config';
7 +
import { Express } from 'express';
8 +
import { createApp } from '../../src/createApp';
9 +

10 +
let prisma: PrismaClient;
11 +
let app: Express;
12 +

13 +
test.before(() => {
14 +
  process.env.NODE_ENV = 'test';
15 +
  process.env.JWT_SECRET = 'test-secret-key';
16 +

17 +
  const connectionString = process.env.DATABASE_URL || 'postgres://user:password@orbit_db:5432/orbit_test';
18 +
  const adapter = new PrismaPg({ connectionString });
19 +
  prisma = new PrismaClient({ adapter });
20 +

21 +
  // Create Express app with test Prisma client
22 +
  app = createApp(prisma);
23 +
});
24 +

25 +
test.beforeEach(async () => {
26 +
  // Clean database before each test
27 +
  try {
28 +
    await prisma.user.deleteMany({});
29 +
  } catch (err) {
30 +
    console.error('Error cleaning test DB:', err);
31 +
  }
32 +
});
33 +

34 +
test.after.always(async () => {
35 +
  await prisma?.$disconnect();
36 +
});
37 +

38 +
test("POST /users creates a new user and returns JWT token", async (t) => {
39 +
  const userData = {
40 +
    email: "falamansa@example.com",
41 +
    firstName: "Fala",
42 +
    lastName: "Mansa",
43 +
    password: "IscreviSeuNomeNaAreia"
44 +
  };
45 +

46 +
  const response = await request(app)
47 +
    .post('/users')
48 +
    .send(userData)
49 +
    .expect('Content-Type', /json/)
50 +
    .expect(201);
51 +

52 +
  // Should return a JWT token
53 +
  t.truthy(response.body.token);
54 +

55 +
  // Verify the token is valid
56 +
  const decoded = jwt.verify(response.body.token, process.env.JWT_SECRET!) as any;
57 +
  t.is(decoded.email, userData.email);
58 +
  t.truthy(decoded.userId);
59 +

60 +
  // Verify user was created in database
61 +
  const dbUser = await prisma.user.findUnique({
62 +
    where: { email: userData.email }
63 +
  });
64 +
  t.truthy(dbUser);
65 +
  t.is(dbUser!.email, userData.email);
66 +
  t.is(dbUser!.firstName, userData.firstName);
67 +
  t.is(dbUser!.lastName, userData.lastName);
68 +
});
69 +

70 +
test("POST /users returns 400 for missing required fields", async (t) => {
71 +
  const response = await request(app)
72 +
    .post('/users')
73 +
    .send({
74 +
      email: "invalid@example.com"
75 +
      // Missing firstName and password
76 +
    })
77 +
    .expect('Content-Type', /json/)
78 +
    .expect(400);
79 +

80 +
  t.truthy(response.body.error);
81 +
  t.is(response.body.error, "Campos faltantes"); // TODO: i18n?
82 +
  t.truthy(response.body.missing);
83 +
  t.true(response.body.missing.includes('password'));
84 +
  t.true(response.body.missing.includes('firstName'));
85 +
});
86 +

87 +
test("POST /users returns 409 for duplicate email", async (t) => {
88 +
  const email = "duplicate@example.com";
89 +

90 +
  // Create first user
91 +
  await prisma.user.create({
92 +
    data: {
93 +
      email,
94 +
      firstName: "First",
95 +
      lastName: "User",
96 +
      encryptedPassword: "$2a$10$test"
97 +
    }
98 +
  });
99 +

100 +
  // Try to create second user with same email
101 +
  const response = await request(app)
102 +
    .post('/users')
103 +
    .send({
104 +
      email,
105 +
      firstName: "Second",
106 +
      lastName: "User",
107 +
      password: "hunter2"
108 +
    })
109 +
    .expect('Content-Type', /json/)
110 +
    .expect(409);
111 +

112 +
  t.truthy(response.body.error);
113 +
});
114 +

115 +
test("createApp successfully integrates with Prisma and Express", async (t) => {
116 +
  // Test that the app factory works correctly
117 +
  const testApp = createApp(prisma);
118 +

119 +
  t.truthy(testApp);
120 +
  t.is(typeof testApp.use, 'function');
121 +
  t.is(typeof testApp.listen, 'function');
122 +

123 +
  // Verify the app has the prisma client in locals
124 +
  t.is(testApp.locals.prisma, prisma);
125 +
});
/dev/null → api/tests/users/delete.test.ts
1 +
import test from "ava";
2 +
import { PrismaClient } from '@prisma/client';
3 +
import { PrismaPg } from '@prisma/adapter-pg';
4 +
import request from 'supertest';
5 +
import bcrypt from 'bcryptjs';
6 +
import 'dotenv/config';
7 +
import { Express } from 'express';
8 +
import { createApp } from '../../src/createApp';
9 +

10 +
let prisma: PrismaClient;
11 +
let app: Express;
12 +

13 +
test.before(() => {
14 +
  process.env.NODE_ENV = 'test';
15 +

16 +
  const connectionString = process.env.DATABASE_URL || 'postgres://user:password@orbit_db:5432/orbit_test';
17 +
  const adapter = new PrismaPg({ connectionString });
18 +
  prisma = new PrismaClient({ adapter });
19 +

20 +
  // Create Express app with test Prisma client
21 +
  app = createApp(prisma);
22 +
});
23 +

24 +
test.beforeEach(async () => {
25 +
  // Clean database before each test
26 +
  try {
27 +
    await prisma.user.deleteMany({});
28 +
  } catch (err) {
29 +
    console.error('Error cleaning test DB:', err);
30 +
  }
31 +
});
32 +

33 +
test.after.always(async () => {
34 +
  await prisma?.$disconnect();
35 +
});
36 +

37 +
//test("DELETE /users/:id deletes a user", async (t) => {
38 +
//  t.pass()
39 +
//  // Create a user first
40 +
//  const user = await prisma.user.create({
41 +
//    data: {
42 +
//      email: "delete@example.com",
43 +
//      firstName: "Delete",
44 +
//      lastName: "Me",
45 +
//      encryptedPassword: bcrypt.hashSync("password", 10)
46 +
//    }
47 +
//  });
48 +
//
49 +
//  await request(app)
50 +
//    .delete(`/users/${user.id}`)
51 +
//    .expect(204);
52 +
//
53 +
//  // Verify user was deleted
54 +
//  const dbUser = await prisma.user.findUnique({
55 +
//    where: { id: user.id }
56 +
//  });
57 +
//  t.is(dbUser, null);
58 +
//});
/dev/null → api/tests/users/fetch.test.ts
1 +
import test from "ava";
2 +
import { PrismaClient } from '@prisma/client';
3 +
import { PrismaPg } from '@prisma/adapter-pg';
4 +
import request from 'supertest';
5 +
import bcrypt from 'bcryptjs';
6 +
import 'dotenv/config';
7 +
import { Express } from 'express';
8 +
import { createApp } from '../../src/createApp';
9 +

10 +
let prisma: PrismaClient;
11 +
let app: Express;
12 +

13 +
test.before(() => {
14 +
  process.env.NODE_ENV = 'test';
15 +

16 +
  const connectionString = process.env.DATABASE_URL || 'postgres://user:password@orbit_db:5432/orbit_test';
17 +
  const adapter = new PrismaPg({ connectionString });
18 +
  prisma = new PrismaClient({ adapter });
19 +

20 +
  // Create Express app with test Prisma client
21 +
  app = createApp(prisma);
22 +
});
23 +

24 +
test.beforeEach(async () => {
25 +
  // Clean database before each test
26 +
  try {
27 +
    await prisma.user.deleteMany({});
28 +
  } catch (err) {
29 +
    console.error('Error cleaning test DB:', err);
30 +
  }
31 +
});
32 +

33 +
test.after.always(async () => {
34 +
  await prisma?.$disconnect();
35 +
});
36 +

37 +
//test("GET /users/:id retrieves a user", async (t) => {
38 +
//  t.pass()
39 +
//  // Create a user first
40 +
//  const user = await prisma.user.create({
41 +
//    data: {
42 +
//      email: "get@example.com",
43 +
//      firstName: "Get",
44 +
//      lastName: "User",
45 +
//      encryptedPassword: bcrypt.hashSync("password", 10)
46 +
//    }
47 +
//  });
48 +
//
49 +
//  const response = await request(app)
50 +
//    .get(`/users/${user.id}`)
51 +
//    .expect('Content-Type', /json/)
52 +
//    .expect(200);
53 +
//
54 +
//  t.is(response.body.id, user.id);
55 +
//  t.is(response.body.email, user.email);
56 +
//  t.is(response.body.firstName, user.firstName);
57 +
//  t.is(response.body.lastName, user.lastName);
58 +
//  t.falsy(response.body.encryptedPassword); // Should not expose password
59 +
//});
60 +
//
61 +
//test("GET /users/:id returns 404 for non-existent user", async (t) => {
62 +
//  const response = await request(app)
63 +
//    .get('/users/999999')
64 +
//    .expect('Content-Type', /json/)
65 +
//    .expect(404);
66 +
//
67 +
//  t.truthy(response.body.error);
68 +
//});
/dev/null → api/tests/users/update.test.ts
1 +
import test from "ava";
2 +
import { PrismaClient } from '@prisma/client';
3 +
import { PrismaPg } from '@prisma/adapter-pg';
4 +
import request from 'supertest';
5 +
import bcrypt from 'bcryptjs';
6 +
import 'dotenv/config';
7 +
import { Express } from 'express';
8 +
import { createApp } from '../../src/createApp';
9 +

10 +
let prisma: PrismaClient;
11 +
let app: Express;
12 +

13 +
test.before(() => {
14 +
  process.env.NODE_ENV = 'test';
15 +

16 +
  const connectionString = process.env.DATABASE_URL || 'postgres://user:password@orbit_db:5432/orbit_test';
17 +
  const adapter = new PrismaPg({ connectionString });
18 +
  prisma = new PrismaClient({ adapter });
19 +

20 +
  // Create Express app with test Prisma client
21 +
  app = createApp(prisma);
22 +
});
23 +

24 +
test.beforeEach(async () => {
25 +
  // Clean database before each test
26 +
  try {
27 +
    await prisma.user.deleteMany({});
28 +
  } catch (err) {
29 +
    console.error('Error cleaning test DB:', err);
30 +
  }
31 +
});
32 +

33 +
test.after.always(async () => {
34 +
  await prisma?.$disconnect();
35 +
});
36 +

37 +
test("PUT /users/:id updates user profile", async (t) => {
38 +
  // Create a user first
39 +
  const user = await prisma.user.create({
40 +
    data: {
41 +
      email: "update@example.com",
42 +
      firstName: "Original",
43 +
      lastName: "Name",
44 +
      encryptedPassword: bcrypt.hashSync("password", 10)
45 +
    }
46 +
  });
47 +

48 +
  const updateData = {
49 +
    firstName: "Updated",
50 +
    lastName: "Profile"
51 +
  };
52 +

53 +
  // TODO: Gotta check why its failing. Most likely due to the
54 +
  // cors/credentials: true line
55 +
  const response = await request(app)
56 +
    .put(`/users/${user.id}`)
57 +
    .send(updateData)
58 +
    .expect('Content-Type', /json/)
59 +
    .expect(200);
60 +

61 +
  t.is(response.body.user.firstName, updateData.firstName);
62 +
  t.is(response.body.user.lastName, updateData.lastName);
63 +
  t.is(response.body.user.email, user.email); // Should remain unchanged
64 +

65 +
  // Verify in database
66 +
  const dbUser = await prisma.user.findUnique({
67 +
    where: { id: user.id }
68 +
  });
69 +

70 +
  t.is(dbUser!.firstName, updateData.firstName);
71 +
  t.is(dbUser!.lastName, updateData.lastName);
72 +
});
73 +

74 +
test("PUT /users/:id returns 404 for non-existent user", async (t) => {
75 +
  const response = await request(app)
76 +
    .put('/users/999999')
77 +
    .send({
78 +
      firstName: "Updated",
79 +
      lastName: "Name"
80 +
    })
81 +
    .expect('Content-Type', /json/)
82 +
    .expect(404);
83 +

84 +
  t.truthy(response.body.error);
85 +
});
/dev/null → api/tsconfig.test.json
1 +
{
2 +
  "extends": "./tsconfig.json",
3 +
  "compilerOptions": {
4 +
    "module": "ESNext",
5 +
    "moduleResolution": "node",
6 +
    "allowImportingTsExtensions": true,
7 +
    "resolveJsonModule": true,
8 +
    "noEmit": true
9 +
  },
10 +
  "ts-node": {
11 +
    "esm": true,
12 +
    "experimentalSpecifierResolution": "node",
13 +
    "transpileOnly": true,
14 +
    "require": ["tsconfig-paths/register"]
15 +
  }
16 +
}