-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feat/testing approaches #61
Changes from 3 commits
b773eb1
15e34c3
08d4a1b
628abc4
22aa7e7
59eca7b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
G0maa marked this conversation as resolved.
Show resolved
Hide resolved
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,30 +1,29 @@ | ||
import { ContextIdFactory } from "@nestjs/core"; | ||
import { Test, TestingModule } from "@nestjs/testing"; | ||
import { AppModule } from "./app.module"; | ||
import { TestManager } from "../test/TestManager"; | ||
import { AppResolver } from "./app.resolver"; | ||
import { AppService } from "./app.service"; | ||
import { DrizzleModule } from "./drizzle/drizzle.module"; | ||
|
||
describe("AppService", () => { | ||
describe("[GraphQL] [IntegrationTesting] AppResolver", () => { | ||
let testManager = new TestManager(); | ||
let appResolver: AppResolver; | ||
|
||
beforeEach(async () => { | ||
// TODO: create proper test module / class. | ||
const app: TestingModule = await Test.createTestingModule({ | ||
imports: [AppModule], | ||
}).compile(); | ||
beforeAll(async () => { | ||
await testManager.beforeAll(); | ||
|
||
// TODO: are there a better handling for this? @xUser5000 | ||
const contextId = ContextIdFactory.create(); | ||
jest.spyOn(ContextIdFactory, "getByRequest").mockImplementation( | ||
() => contextId, | ||
); | ||
|
||
appResolver = await app.resolve(AppResolver, contextId); | ||
appResolver = await testManager.app.resolve(AppResolver, contextId); | ||
}); | ||
|
||
describe("root", () => { | ||
it('should return "Hello World!"', () => { | ||
expect(appResolver.hello()).toBe("Hello World!"); | ||
}); | ||
afterAll(async () => { | ||
await testManager.afterAll(); | ||
}); | ||
|
||
it('should return "Hello World!"', async () => { | ||
const result = appResolver.hello(); | ||
expect(result).toBe("Hello World!"); | ||
}); | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
import { ContextIdFactory } from "@nestjs/core"; | ||
G0maa marked this conversation as resolved.
Show resolved
Hide resolved
|
||
import { Test, TestingModule } from "@nestjs/testing"; | ||
import { TestManager } from "../test/TestManager"; | ||
import { AppResolver } from "./app.resolver"; | ||
import { AppService } from "./app.service"; | ||
import { DrizzleService } from "./drizzle/drizzle.service"; | ||
|
||
describe("[GraphQL] [UnitTesting] AppService", () => { | ||
let appService: AppService; | ||
let drizzleService: DrizzleService; | ||
|
||
// Note: we *shouldn't* (?) need TestManager for unit tests. | ||
beforeAll(async () => { | ||
const app: TestingModule = await Test.createTestingModule({ | ||
// Mocking can happen here (if appService has dependencies), | ||
// or add specific mocks to each test case. | ||
providers: [ | ||
AppService, | ||
{ | ||
provide: DrizzleService, | ||
useValue: { | ||
db: { | ||
query: { | ||
users: { | ||
findMany: jest.fn().mockReturnValue([]), | ||
}, | ||
}, | ||
}, | ||
}, | ||
}, | ||
], | ||
}).compile(); | ||
|
||
drizzleService = app.get<DrizzleService>(DrizzleService); | ||
appService = app.get<AppService>(AppService); | ||
}); | ||
|
||
afterAll(async () => {}); | ||
|
||
it('should return "Hello World!"', async () => { | ||
const spy = jest.spyOn(drizzleService.db.query.users, "findMany"); | ||
|
||
const result = await appService.testDb(); | ||
expect(spy).toHaveBeenCalled(); | ||
expect(result).toStrictEqual([]); | ||
}); | ||
}); |
Original file line number | Diff line number | Diff line change | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,63 @@ | ||||||||||||||
import { INestApplication, ValidationPipe } from "@nestjs/common"; | ||||||||||||||
import { ConfigService } from "@nestjs/config"; | ||||||||||||||
import { Test } from "@nestjs/testing"; | ||||||||||||||
import RedisStore from "connect-redis"; | ||||||||||||||
import * as session from "express-session"; | ||||||||||||||
import * as passport from "passport"; | ||||||||||||||
import { createClient } from "redis"; | ||||||||||||||
import { AppModule } from "../src/app.module"; | ||||||||||||||
|
||||||||||||||
export class TestManager { | ||||||||||||||
// biome-ignore lint/suspicious/noExplicitAny: it is any. | ||||||||||||||
public httpServer: any; | ||||||||||||||
public app: INestApplication; | ||||||||||||||
G0maa marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||||||||||
|
||||||||||||||
// TODO: Find a way to abstract this logic, found in main.ts too. | ||||||||||||||
async beforeAll(): Promise<void> { | ||||||||||||||
const moduleRef = await Test.createTestingModule({ | ||||||||||||||
imports: [AppModule], | ||||||||||||||
}).compile(); | ||||||||||||||
this.app = moduleRef.createNestApplication(); | ||||||||||||||
|
||||||||||||||
const configService = this.app.get(ConfigService); | ||||||||||||||
|
||||||||||||||
this.app.useGlobalPipes( | ||||||||||||||
new ValidationPipe({ | ||||||||||||||
transform: true, | ||||||||||||||
whitelist: true, | ||||||||||||||
}), | ||||||||||||||
); | ||||||||||||||
|
||||||||||||||
const redisClient = await createClient({ | ||||||||||||||
url: String(configService.getOrThrow("REDIS_URL")), | ||||||||||||||
}).connect(); | ||||||||||||||
|
||||||||||||||
this.app.use( | ||||||||||||||
session({ | ||||||||||||||
secret: configService.getOrThrow<string>("SESSION_SECRET"), | ||||||||||||||
resave: false, | ||||||||||||||
saveUninitialized: false, | ||||||||||||||
cookie: { | ||||||||||||||
maxAge: configService.getOrThrow<number>("COOKIE_MAX_AGE"), | ||||||||||||||
httpOnly: true, | ||||||||||||||
}, | ||||||||||||||
store: new RedisStore({ | ||||||||||||||
client: redisClient, | ||||||||||||||
}), | ||||||||||||||
}), | ||||||||||||||
Comment on lines
+37
to
+48
Check warning Code scanning / CodeQL Clear text transmission of sensitive cookie Medium test
Sensitive cookie sent without enforcing SSL encryption.
Copilot Autofix AI 10 days ago To fix the problem, we need to ensure that the session cookie is only transmitted over HTTPS by setting the
Suggested changeset
1
apps/api/test/TestManager.ts
Copilot is powered by AI and may make mistakes. Always verify output.
Refresh and try again.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||||||||||||||
); | ||||||||||||||
|
||||||||||||||
this.app.use(passport.initialize()); | ||||||||||||||
this.app.use(passport.session()); | ||||||||||||||
this.app.enableCors(); | ||||||||||||||
|
||||||||||||||
this.httpServer = this.app.getHttpServer(); | ||||||||||||||
await this.app.init(); | ||||||||||||||
} | ||||||||||||||
|
||||||||||||||
async afterAll() { | ||||||||||||||
await this.app.close(); | ||||||||||||||
} | ||||||||||||||
|
||||||||||||||
// Helper functions can be added here if needed e.g. generateUser(). | ||||||||||||||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
import "tsconfig-paths/register"; | ||
|
||
import { createClient } from "redis"; | ||
import { TestManager } from "./TestManager"; | ||
|
||
export default async (): Promise<void> => { | ||
console.log("# Started Jest globalSetup."); | ||
const testManager = new TestManager(); | ||
|
||
await testManager.beforeAll(); | ||
|
||
await testManager.app.init(); | ||
|
||
// TODO: Apply Database migrations/seeders. | ||
G0maa marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
await testManager.app.close(); | ||
|
||
// Delete records in redis. | ||
const client = createClient(); | ||
await client.connect(); | ||
await client.flushAll(); | ||
console.log("# Finished Jest globalSetup."); | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
import "tsconfig-paths/register"; | ||
|
||
import { createClient } from "redis"; | ||
import { TestManager } from "./TestManager"; | ||
|
||
export default async (): Promise<void> => { | ||
console.log("# Started Jest globalTeardown."); | ||
const testManager = new TestManager(); | ||
|
||
await testManager.beforeAll(); | ||
|
||
await testManager.app.init(); | ||
|
||
// TODO: Apply Database migrations/seeders. | ||
|
||
await testManager.app.close(); | ||
|
||
// Delete records in redis. | ||
const client = createClient(); | ||
await client.connect(); | ||
await client.flushAll(); | ||
console.log("# Finished Jest globalTeardown."); | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
appears when trying to run
jest
.Also
test:e2e
shows a similar message:There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@bassiounix
The intention of this branch is not to test. The intention is to show developer working on Disworse HOW to test. With examples on Unit, E2E, and ((kind of)) integration tests.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also on the Jest error, I never managed to fix it, I usually silence it with
--forceExit
.