diff --git a/package.json b/package.json index 88142bd3..11b9f405 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,7 @@ "make-docs": "./node_modules/.bin/jsdoc index.js lib -r -R README.md -u ./doc -c .jsdoc.json --verbose -d ./jsdoc", "publish-docs": "gh-pages -d jsdoc --repo git@github.com:internxt/bridge.git", "build": "tsc", - "test": "jest --testPathIgnorePatterns ./tests/lib/mongo", + "test": "jest --testPathIgnorePatterns ./tests/lib/mongo ./tests/lib/e2e", "test:cov": "jest --coverage", "test:e2e": "NODE_ENV=test jest --config ./tests/lib/e2e/jest-e2e.json --setupFiles dotenv/config", "test-mongo-init": "ts-node ./tests/lib/mongo/init", diff --git a/tests/lib/e2e/buckets/buckets.e2e-spec.ts b/tests/lib/e2e/buckets/buckets.e2e-spec.ts new file mode 100644 index 00000000..6f2d6c27 --- /dev/null +++ b/tests/lib/e2e/buckets/buckets.e2e-spec.ts @@ -0,0 +1,115 @@ +import { createTestUser, deleteTestUser, getAuth, testUser, } from '../utils' + +import { engine, testServer } from '../setup' + + + +describe('Bridge E2E Tests', () => { + + beforeAll(async () => { + await engine.storage.models.Bucket.deleteMany({}) + }) + + afterAll(async () => { + await engine.storage.models.Bucket.deleteMany({}) + }) + + beforeEach(() => { + jest.clearAllMocks() + }) + + describe('Buckets Management', () => { + + beforeAll(async () => { + await createTestUser(engine.storage) + }) + + afterAll(async () => { + await deleteTestUser(engine.storage) + }) + + describe('Bucket creation v1', () => { + + it('should create a bucket with name and pubkeys', async () => { + + // Act + const response = await testServer + .post('/buckets') + .set('Authorization', getAuth(testUser)) + .send({ + pubkeys: ['031a259ee122414f57a63bbd6887ee17960e9106b0adcf89a298cdad2108adf4d9'], + name: 'test-bucket-name' + }) + + // Assert + expect(response.status).toBe(201) + expect(response.body).toHaveProperty('id') + + const buckets = await engine.storage.models.Bucket.find({ _id: response.body.id }) + expect(buckets).toHaveLength(1) + + }) + }) + + + describe('Bucket update v1', () => { + + it('should be able to update a bucket to empty pubkeys', async () => { + // Arrange + const { body: bucket } = await testServer + .post('/buckets') + .set('Authorization', getAuth(testUser)) + .send({ + pubkeys: ['031a259ee122414f57a63bbd6887ee17960e9106b0adcf89a298cdad2108adf4d9'], + name: 'test-bucket-name-1' + }) + .expect(201); + + // Act + + + const response = await testServer + .patch(`/buckets/${bucket.id}`) + .set('Authorization', getAuth(testUser)) + .send({ pubkeys: [] }) + + + // Assert + expect(response.status).toBe(200); + + const dbBucket = await engine.storage.models.Bucket.findOne({ _id: response.body.id }) + expect(dbBucket.toObject().pubkeys).toEqual([]) + + }) + }) + + describe('Bucket deletion v1', () => { + it('should be able to delete a bucket', async () => { + + // Arrange: Create a bucket + const { body: bucket } = await testServer + .post('/buckets') + .set('Authorization', getAuth(testUser)) + .send({ + pubkeys: ['031a259ee122414f57a63bbd6887ee17960e9106b0adcf89a298cdad2108adf4d9'], + name: 'test-bucket-name-2' + }) + .expect(201); + + // Act: Delete the bucket + const response = await testServer + .delete(`/buckets/${bucket.id}`) + .set('Authorization', getAuth(testUser)) + + + // Assert + expect(response.status).toBe(204) + const buckets = await engine.storage.models.Bucket.findOne({ _id: bucket.id }) + expect(buckets).toBeNull() + + }) + }) + }) + +}) + diff --git a/tests/lib/e2e/global-teardown.ts b/tests/lib/e2e/global-teardown.ts new file mode 100644 index 00000000..c2c603d7 --- /dev/null +++ b/tests/lib/e2e/global-teardown.ts @@ -0,0 +1,3 @@ +export default async () => { + process.emit('SIGINT') +} diff --git a/tests/lib/e2e/jest-e2e.json b/tests/lib/e2e/jest-e2e.json index e9d912f3..5fddc0ec 100644 --- a/tests/lib/e2e/jest-e2e.json +++ b/tests/lib/e2e/jest-e2e.json @@ -1,6 +1,7 @@ { "moduleFileExtensions": ["js", "json", "ts"], "rootDir": ".", + "globalTeardown": "./global-teardown.ts", "testEnvironment": "node", "testRegex": ".e2e-spec.ts$", "transform": { diff --git a/tests/lib/e2e/setup.ts b/tests/lib/e2e/setup.ts new file mode 100644 index 00000000..d7d8fa45 --- /dev/null +++ b/tests/lib/e2e/setup.ts @@ -0,0 +1,14 @@ +import supertest from 'supertest'; +import { checkConnection } from './utils'; + +if (process.env.inxtbridge_server__port !== '0') { + console.warn('Warning: inxtbridge_server__port is not set to 0, this may cause conflicts with the test server'); +} +// Remove jest options from process.argv +process.argv = process.argv.slice(0, 2); +export const engine = require('../../../bin/storj-bridge.ts'); + +checkConnection(engine.storage); + +export const testServer = supertest(engine.server.app); + diff --git a/tests/lib/e2e/users.fixtures.ts b/tests/lib/e2e/users.fixtures.ts index feec1e36..fa14f201 100644 --- a/tests/lib/e2e/users.fixtures.ts +++ b/tests/lib/e2e/users.fixtures.ts @@ -40,3 +40,4 @@ const usersTest: MongoUserModel[] = [ export const users: MongoUserModel[] = usersTest; export const userFixtures: User[] = usersTest.map(formatUser); +export const [testUser] = users diff --git a/tests/lib/e2e/e2e-spec.ts b/tests/lib/e2e/users/users.e2e-spec.ts similarity index 59% rename from tests/lib/e2e/e2e-spec.ts rename to tests/lib/e2e/users/users.e2e-spec.ts index 93519e32..6702da52 100644 --- a/tests/lib/e2e/e2e-spec.ts +++ b/tests/lib/e2e/users/users.e2e-spec.ts @@ -1,8 +1,8 @@ -import supertest from 'supertest' -import { checkConnection, cleanDataBase, createTestUser, getAuth, testUser } from './utils' +import { getAuth, testUser, } from '../utils' -// NB: Mock external dependencies import sendGridMail from '@sendgrid/mail' +import { engine, testServer } from '../setup' + // NB: Mock SendGrid jest.mock('@sendgrid/mail', () => ({ @@ -13,117 +13,18 @@ jest.mock('@sendgrid/mail', () => ({ // NB: Mock JWT verification jest.mock('jsonwebtoken', () => ({ verify: jest.fn((_, __, ___, cb) => cb(null, {})) })) - -// Remove jest args so there is no conflict with storj-bridge -process.argv = process.argv.slice(0, 2) -const engine = require('../../../bin/storj-bridge') - -engine.mailer.dispatchSendGrid = jest.fn((_, __, ___, cb) => { sendGridMail.send(null as any, null as any, cb) }) - - - -checkConnection(engine.storage) - describe('Bridge E2E Tests', () => { - beforeEach(() => { - jest.clearAllMocks() - }) - beforeAll(async () => { - await cleanDataBase(engine.storage) + await engine.storage.models.User.deleteMany({}) }) afterAll(async () => { - await cleanDataBase(engine.storage) + await engine.storage.models.User.deleteMany({}) }) - describe('Buckets Management', () => { - - - beforeAll(async () => { - await createTestUser(engine.storage) - }) - - describe('Bucket creation v1', () => { - - it('should create a bucket with name and pubkeys', async () => { - - // Act - const response = await supertest(engine.server.app) - .post('/buckets') - .set('Authorization', getAuth(testUser)) - .send({ - pubkeys: ['031a259ee122414f57a63bbd6887ee17960e9106b0adcf89a298cdad2108adf4d9'], - name: 'test-bucket-name' - }) - - // Assert - expect(response.status).toBe(201) - expect(response.body).toHaveProperty('id') - - const buckets = await engine.storage.models.Bucket.find({ _id: response.body.id }) - expect(buckets).toHaveLength(1) - - }) - }) - - - describe('Bucket update v1', () => { - - it('should be able to update a bucket to empty pubkeys', async () => { - // Arrange - const { body: bucket } = await supertest(engine.server.app) - .post('/buckets') - .set('Authorization', getAuth(testUser)) - .send({ - pubkeys: ['031a259ee122414f57a63bbd6887ee17960e9106b0adcf89a298cdad2108adf4d9'], - name: 'test-bucket-name-1' - }) - .expect(201); - - // Act - const response = await supertest(engine.server.app) - .patch(`/buckets/${bucket.id}`) - .set('Authorization', getAuth(testUser)) - .send({ pubkeys: [] }) - - - // Assert - expect(response.status).toBe(200); - - const dbBucket = await engine.storage.models.Bucket.findOne({ _id: response.body.id }) - expect(dbBucket.toObject().pubkeys).toEqual([]) - - }) - }) - - describe('Bucket deletion v1', () => { - it('should be able to delete a bucket', async () => { - - // Arrange: Create a bucket - const { body: bucket } = await supertest(engine.server.app) - .post('/buckets') - .set('Authorization', getAuth(testUser)) - .send({ - pubkeys: ['031a259ee122414f57a63bbd6887ee17960e9106b0adcf89a298cdad2108adf4d9'], - name: 'test-bucket-name-2' - }) - .expect(201); - - // Act: Delete the bucket - const response = await supertest(engine.server.app) - .delete(`/buckets/${bucket.id}`) - .set('Authorization', getAuth(testUser)) - - - // Assert - expect(response.status).toBe(204) - const buckets = await engine.storage.models.Bucket.findOne({ _id: bucket.id }) - expect(buckets).toBeNull() - - }) - }) + beforeEach(() => { + jest.clearAllMocks() }) describe('Users Management', () => { @@ -132,7 +33,7 @@ describe('Bridge E2E Tests', () => { it('should create a user with email and password', async () => { // Act - const response = await supertest(engine.server.app) + const response = await testServer .post('/users') .send({ email: 'test' + testUser.email, password: testUser.hashpass }) @@ -140,6 +41,7 @@ describe('Bridge E2E Tests', () => { expect(response.status).toBe(201); const users = await engine.storage.models.User.find({ _id: response.body.id }) expect(users).toHaveLength(1) + expect(users[0].toObject().activated).toBe(true) // expect(dispatchSendGridMock).toHaveBeenCalled() @@ -150,14 +52,17 @@ describe('Bridge E2E Tests', () => { describe('User deletion v1', () => { it('should be able to request a user deactivation', async () => { + // Arrange: Mock SendGrid call + engine.mailer.dispatchSendGrid = jest.fn((_, __, ___, cb) => { sendGridMail.send(null as any, null as any, cb) }) + // Arrange: Create User - const { body: user } = await supertest(engine.server.app) + const { body: user } = await testServer .post('/users') .send({ email: 'request_deactivation' + testUser.email, password: testUser.hashpass, }) .expect(201); // Act: Request Deactivation - const response = await supertest(engine.server.app) + const response = await testServer .delete(`/users/${user.email}?deactivator=test-deactivator-token-request-deactivation&redirect=/`) .set('Authorization', getAuth({ email: user.email, hashpass: testUser.hashpass })) @@ -177,7 +82,7 @@ describe('Bridge E2E Tests', () => { it('should be able to confirm a user deactivation', async () => { // Arrange: Create User - const { body: user } = await supertest(engine.server.app) + const { body: user } = await testServer .post('/users') .send({ email: 'confirm_deactivation' + testUser.email, password: testUser.hashpass, }) .expect(201); @@ -185,13 +90,13 @@ describe('Bridge E2E Tests', () => { // Arrange: Request Deactivation const token = 'test-deactivator-token-confirm-deactivation' - await supertest(engine.server.app) + await testServer .delete(`/users/${user.email}?deactivator=${token}&redirect=/`) .set('Authorization', getAuth({ email: user.email, hashpass: testUser.hashpass })) .expect(200) // Act: Confirm Deactivation - const response = await supertest(engine.server.app).get(`/deactivations/${token}`) + const response = await testServer.get(`/deactivations/${token}`) // Assert expect(response.status).toBe(200) @@ -203,7 +108,7 @@ describe('Bridge E2E Tests', () => { describe('User creation v2', () => { it('should create a user with email and password', async () => { // Act: Create a user - const response = await supertest(engine.server.app) + const response = await testServer .post('/v2/users') .send({ email: 'test_v2' + testUser.email, password: testUser.hashpass }) @@ -223,7 +128,7 @@ describe('Bridge E2E Tests', () => { // Arrange: Create User const testEmail = 'request_deactivation_v2' + testUser.email - const { body: user } = await supertest(engine.server.app) + const { body: user } = await testServer .post('/v2/users') .send({ email: testEmail, password: testUser.hashpass, }) // .expect(201) @@ -231,7 +136,7 @@ describe('Bridge E2E Tests', () => { // Act: Request Deactivation - const response = await supertest(engine.server.app) + const response = await testServer .delete(`/v2/users/request-deactivate?deactivator=test-deactivator-token-request-deactivation-v2&redirect=/`) .set('Authorization', getAuth({ email: testEmail, hashpass: testUser.hashpass })) @@ -253,7 +158,7 @@ describe('Bridge E2E Tests', () => { // Arrange: Create User const testEmail = 'confirm_deactivation_v2' + testUser.email - const { body: user } = await supertest(engine.server.app) + const { body: user } = await testServer .post('/v2/users') .send({ email: testEmail, password: testUser.hashpass, }) // .expect(201) @@ -262,14 +167,14 @@ describe('Bridge E2E Tests', () => { // Arrange: Request Deactivation const token = 'test-deactivator-token-confirm-deactivation-v2' - await supertest(engine.server.app) + await testServer .delete(`/v2/users/request-deactivate?deactivator=${token}&redirect=/`) .set('Authorization', getAuth({ email: testEmail, hashpass: testUser.hashpass })) .expect(200) // Act: Confirm Deactivation - const response = await supertest(engine.server.app).delete(`/v2/users/confirm-deactivate/${token}`) + const response = await testServer.delete(`/v2/users/confirm-deactivate/${token}`) // Assert expect(response.status).toBe(200); @@ -286,7 +191,7 @@ describe('Bridge E2E Tests', () => { // Arrange: Create User const testEmail = 'update_user_email_v2' + testUser.email - const { body: user } = await supertest(engine.server.app) + const { body: user } = await testServer .post('/v2/users') .send({ email: testEmail, password: testUser.hashpass, }) // .expect(201) @@ -295,7 +200,7 @@ describe('Bridge E2E Tests', () => { // Act: Update User Email const newEmail = 'new_email_v2' + testUser.email - const response = await supertest(engine.server.app) + const response = await testServer .patch(`/v2/gateway/users/${user.id}`) .set('Authorization', `Bearer fake-token`) .send({ email: newEmail }) @@ -310,8 +215,6 @@ describe('Bridge E2E Tests', () => { }) }) }) - afterAll(() => { - process.emit('SIGINT') - }) + }) diff --git a/tests/lib/e2e/utils.ts b/tests/lib/e2e/utils.ts index 717d44ba..fd790cc4 100644 --- a/tests/lib/e2e/utils.ts +++ b/tests/lib/e2e/utils.ts @@ -1,7 +1,9 @@ -import { MongoUserModel, users } from './users.fixtures' -export const [testUser] = users +import { type Test, type SuperTest } from 'supertest' +import { MongoUserModel, testUser, } from './users.fixtures' +export * from './users.fixtures' + export const checkConnection = (storage: any) => { if (!storage.connection.options.dbName.includes('test')) { throw new Error("For caution test database must include test in it's name"); @@ -42,17 +44,8 @@ export const deleteTestUser = async (storage: any): Promise => { } + export const getAuth = (user: { email: string, hashpass: string }) => { const credential = Buffer.from(`${user.email}:${user.hashpass}`).toString('base64'); return `Basic ${credential}`; } - - -export const cleanDataBase = async (storage: any) => { - checkConnection(storage) - - await Promise.all([ - storage.models.User.deleteMany({}), - storage.models.Bucket.deleteMany({}) - ]) -} \ No newline at end of file