Skip to content

Commit

Permalink
Merge pull request #16 from mathiasberggren/feature/integration-tests…
Browse files Browse the repository at this point in the history
…. Solves #17

[Monorepo] Enable Integration tests
  • Loading branch information
rasouza authored Apr 19, 2024
2 parents 4cc4237 + 44791b0 commit 440f120
Show file tree
Hide file tree
Showing 30 changed files with 25,544 additions and 17,794 deletions.
6 changes: 6 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ jobs:
with:
fetch-depth: 2

- name: Enable Corepack
run: corepack enable

- name: Setup Node.js environment
uses: actions/setup-node@v4
with:
Expand All @@ -39,3 +42,6 @@ jobs:

- name: Test
run: yarn test

- name: Integration Test
run: yarn test:e2e
13 changes: 10 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,10 @@ testem.log
.DS_Store
Thumbs.db

.nx/cache

# Expo
node_modules/
.expo/
.yarn/
.yarn/*
dist/
npm-debug.*
*.jks
Expand Down Expand Up @@ -125,3 +123,12 @@ yarn-error.log
/coverage

.turbo

# Yarn Berry
.pnp.*
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/sdks
!.yarn/versions
1 change: 0 additions & 1 deletion .vscode/extensions.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
{
"recommendations": [
"nrwl.angular-console",
"esbenp.prettier-vscode",
"firsttris.vscode-jest-runner",
"vivaxy.vscode-conventional-commits",
Expand Down
893 changes: 893 additions & 0 deletions .yarn/releases/yarn-4.1.1.cjs

Large diffs are not rendered by default.

9 changes: 9 additions & 0 deletions .yarnrc.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
nodeLinker: node-modules

supportedArchitectures:
cpu:
- current
- x64
- arm64

yarnPath: .yarn/releases/yarn-4.1.1.cjs
7 changes: 7 additions & 0 deletions apps/api/.env.development
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Environment variables declared in this file are automatically made available to Prisma.
# See the documentation for more detail: https://pris.ly/d/prisma-schema#accessing-environment-variables-from-the-schema

# Prisma supports the native connection string format for PostgreSQL, MySQL, SQLite, SQL Server, MongoDB and CockroachDB.
# See the documentation for all the connection string options: https://pris.ly/d/connection-strings

DATABASE_URL="postgresql://api:admin@localhost:5432/postgres?schema=public"
1 change: 1 addition & 0 deletions apps/api/.env.test
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
DATABASE_URL="postgresql://test:test@localhost:5433/tests"
9 changes: 6 additions & 3 deletions apps/api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,21 @@
"license": "MIT",
"author": "",
"scripts": {
"build": "vite build",
"build": "vite build && yarn prisma generate",
"start": "nest start",
"dev": "vite",
"start:debug": "nest start --debug --watch",
"start:prod": "node dist/main",
"console": "npm run start -- --watch --entryFile repl",
"console": "yarn start -- --watch --entryFile repl",
"db:deploy": "npx prisma migrate deploy",
"db:migrate": "npx prisma migrate dev",
"db:seed": "npx prisma db seed",
"db:studio": "npx prisma studio",
"lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
"test": "jest",
"test:cov": "jest --coverage",
"test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
"test:e2e": "jest --config ./test/jest-e2e.json",
"test:e2e": "dotenv -e .env.test -- jest --config ./test/jest-e2e.json",
"test:watch": "jest --watch"
},
"lint-staged": {
Expand Down Expand Up @@ -63,6 +64,8 @@
"@types/supertest": "^6.0.0",
"@typescript-eslint/eslint-plugin": "^6.0.0",
"@typescript-eslint/parser": "^6.0.0",
"docker-compose": "^0.24.8",
"dotenv-cli": "^7.4.1",
"eslint": "^8.42.0",
"eslint-config-prettier": "^9.0.0",
"eslint-plugin-prettier": "^5.0.0",
Expand Down
6 changes: 5 additions & 1 deletion apps/api/src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,11 @@ import { HttpExceptionFilter } from './http-exception.filter'

@Module({
imports: [
ConfigModule.forRoot({ isGlobal: true, validate }),
ConfigModule.forRoot({
isGlobal: true,
validate,
envFilePath: ['.env', '.env.development']
}),
DatabaseModule,
MoviesModule,
SubscriptionsModule
Expand Down
2 changes: 1 addition & 1 deletion apps/api/src/app/http-exception.filter.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { ExceptionFilter, Catch, ArgumentsHost, HttpException, Logger } from '@nestjs/common'
import { Request, Response } from 'express'

@Catch()
@Catch(HttpException)
export class HttpExceptionFilter implements ExceptionFilter {
constructor (private readonly logger: Logger) {}
catch (exception: HttpException, host: ArgumentsHost) {
Expand Down
5 changes: 5 additions & 0 deletions apps/api/src/database/client.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { PrismaClient } from '@prisma/client'

const prisma = new PrismaClient()

export default prisma
15 changes: 12 additions & 3 deletions apps/api/src/database/factories/company.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,20 @@
import { PrismaClient, Company } from '@prisma/client'
import { Company } from '@prisma/client'
import { Factory } from 'fishery'
import { faker } from '@faker-js/faker'

import prisma from '../client'

export const companyFactory = Factory.define<Company>(({ sequence, onCreate }) => {
onCreate(async (company) => {
const prisma = new PrismaClient()
return await prisma.company.create({ data: company })
return await prisma.company.create({
data: {
// ID is auto-generated
name: company.name,
image: company.image,
createdAt: company.createdAt,
updatedAt: company.updatedAt
}
})
})

return {
Expand Down
6 changes: 3 additions & 3 deletions apps/api/src/database/factories/subscription.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { Company, PrismaClient, Subscription, SubscriptionCredential, User } from '@prisma/client'
import { Company, Subscription, SubscriptionCredential, User } from '@prisma/client'
import { Factory } from 'fishery'

import prisma from '../client'

import { userFactory } from './user'
import { companyFactory } from './company'
import { subscriptionCredentialFactory } from './subscriptionCredential'
Expand All @@ -21,8 +23,6 @@ class SubscriptionFactory extends Factory<ISubscriptionFactory> {

export const subscriptionFactory = SubscriptionFactory.define(({ sequence, onCreate }) => {
onCreate(async (subscription) => {
const prisma = new PrismaClient()

const user = await userFactory.create(subscription.user)
const company = await companyFactory.create(subscription.company)

Expand Down
6 changes: 3 additions & 3 deletions apps/api/src/database/factories/subscriptionCredential.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import { PrismaClient, Subscription, SubscriptionCredential } from '@prisma/client'
import { Subscription, SubscriptionCredential } from '@prisma/client'
import { Factory } from 'fishery'
import { faker } from '@faker-js/faker'

import prisma from '../client'

import { subscriptionFactory } from './subscription'

interface ISubscriptionCredentialFactory extends SubscriptionCredential {
subscription?: Subscription
}
export const subscriptionCredentialFactory = Factory.define<ISubscriptionCredentialFactory>(({ sequence, onCreate }) => {
onCreate(async (credential) => {
const prisma = new PrismaClient()

const subscription = await subscriptionFactory.create(credential.subscription)

return await prisma.subscriptionCredential.create({
Expand Down
15 changes: 12 additions & 3 deletions apps/api/src/database/factories/user.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,23 @@
import { PrismaClient, Subscription, User } from '@prisma/client'
import { Subscription, User } from '@prisma/client'
import { Factory } from 'fishery'
import { faker } from '@faker-js/faker'

import prisma from '../client'

interface IUserFactory extends User {
subscription?: Subscription[]
}
export const userFactory = Factory.define<IUserFactory>(({ sequence, onCreate }) => {
onCreate(async (user) => {
const prisma = new PrismaClient()
return await prisma.user.create({ data: user })
return await prisma.user.create({
data: {
// ID is auto-generated
name: user.name,
email: user.email,
createdAt: user.createdAt,
updatedAt: user.updatedAt
}
})
})
return {
id: sequence,
Expand Down
3 changes: 2 additions & 1 deletion apps/api/src/database/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
// Try Prisma Accelerate: https://pris.ly/cli/accelerate-init

generator client {
provider = "prisma-client-js"
provider = "prisma-client-js"
binaryTargets = ["native", "darwin", "darwin-arm64"]
}

datasource db {
Expand Down
2 changes: 1 addition & 1 deletion apps/api/src/subscriptions/entities/subscription.entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ const SubscriptionResponseSchema = z.object({
id: z.number(),
username: z.string()
// Hides password in any response payload
}).nullable(),
}).nullable().optional(),
createdAt: z.date(),
updatedAt: z.date()
})
Expand Down
16 changes: 11 additions & 5 deletions apps/api/test/app.e2e-spec.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import { Server } from 'net'

import { Test, TestingModule } from '@nestjs/testing'
import { INestApplication } from '@nestjs/common'
import * as request from 'supertest'
import request from 'supertest'

import { AppModule } from './../src/app.module'
import { AppModule } from './../src/app/app.module'

describe('AppController (e2e)', () => {
let app: INestApplication
let app: INestApplication<Server>

beforeEach(async () => {
beforeAll(async () => {
const moduleFixture: TestingModule = await Test.createTestingModule({
imports: [AppModule]
}).compile()
Expand All @@ -16,10 +18,14 @@ describe('AppController (e2e)', () => {
await app.init()
})

afterAll(async () => {
await app.close()
})

it('/ (GET)', () => {
return request(app.getHttpServer())
.get('/')
.expect(200)
.expect('Hello World!')
.expect({ message: 'Hello API' })
})
})
25 changes: 25 additions & 0 deletions apps/api/test/helpers/global-setup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { execSync } from 'child_process'

import dockerCompose from 'docker-compose'

export default async () => {
console.time('⏱️ Global setup time')
try {
console.info('\n🟡 - Starting Docker containers...')
await dockerCompose.upMany(['test_database'])
console.info('🟢 - Containers are ready!')

console.info('🟡 - Waiting for database to be ready...')
await dockerCompose.exec(
'test_database',
['sh', '-c', 'until pg_isready ; do sleep 1; done']
)
console.info('🟢 - Database is ready!')

execSync('dotenv -e .env.test -- yarn db:deploy', { stdio: 'inherit' })
} catch (e) {
console.dir(e)
throw e
}
console.timeEnd('⏱️ Global setup time')
}
5 changes: 5 additions & 0 deletions apps/api/test/helpers/setup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import truncateDb from './truncate-db'

beforeEach(async () => {
await truncateDb()
})
21 changes: 21 additions & 0 deletions apps/api/test/helpers/truncate-db.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { PrismaClient } from '@prisma/client'

const prisma = new PrismaClient()

// From Prisma Doc: https://www.prisma.io/docs/orm/prisma-client/queries/crud#delete-all-records

export default async () => {
const tablenames = await prisma.$queryRaw<Array<{ tablename: string }>>`SELECT tablename FROM pg_tables WHERE schemaname='public'`

const tables = tablenames
.map(({ tablename }: { tablename: string }) => tablename)
.filter((name: string) => name !== '_prisma_migrations')
.map((name: string) => `"public"."${name}"`)
.join(', ')

try {
await prisma.$executeRawUnsafe(`TRUNCATE TABLE ${tables} CASCADE;`)
} catch (error) {
console.log({ error })
}
}
4 changes: 3 additions & 1 deletion apps/api/test/jest-e2e.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,7 @@
"testRegex": ".e2e-spec.ts$",
"transform": {
"^.+\\.(t|j)s$": "ts-jest"
}
},
"setupFilesAfterEnv": ["./helpers/setup.ts"],
"globalSetup": "./helpers/global-setup.ts"
}
Loading

0 comments on commit 440f120

Please sign in to comment.