-
-
Notifications
You must be signed in to change notification settings - Fork 6.2k
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
Sample to run Jest tests using the data-source #9109
Comments
I've manage to find a way to make it work. It's probably not ideal, but does the trick for now. The main issue above is making use of the data-source. The only way I could do that was by relying on a dependency-injection lib. I've used typeDi. I have now 2 places of "absolute truth" when it comes to the data-source. One that's created when the server starts (in the index.ts) and one that's created by the test-case. Since the two never overlap, I just inject it into the TypeDI container and make use of it everywhere I need. To show a little bit of code: the above changes to const initializeDataSource = async (): Promise<DataSource> => {
const dataSource = testDataSource(); // <--- made it a function, because of other reason.
await dataSource
.initialize()
.then(() => Container.set(DataSource, dataSource)); // <--- this is the important line
return dataSource;
}; And now that we have a function that initializes a connection to the testing database, we can use it when writing a test. (tests/user.test.ts) let dataSource: DataSource;
beforeAll(async (): Promise<DataSource> => {
dataSource = await initializeDataSource();
return dataSource;
});
afterAll(async () => dataSource.destroy());
const createUser= `
mutation CreateUser($name: String!) {
createUser(name: $name) {
id
name
}
}
`;
describe("Test the user module", () => {
it("should create a user", async () => {
const user: Partial<User> = {
name: faker.name.jobType()
};
const response = await gqlHelper({ // <--- this is a helper function to call directly the GQL resolver, as a client would.
source: createUser,
variableValues: user
});
expect(response).toMatchObject({
data: {
createUser: user
}
});
}); And now it works because the actual resolver invoked in the test is injecting the user repository, that internally injects the data-source we stored in the TypeDI Container. The repository class changed to this: class UserRepository extends Repository<User> {
private readonly userRepository: Repository<User>;
public constructor(dataSource: DataSource) { // <-- TypeDI knows to inject the DataSource because of its type.
super(User, dataSource.manager);
this.userRepository = dataSource.getRepository(User);
}
public async create(data: Partial<User>): Promise<User> {
const user = Object.assign(new User(), data);
.
return this.userRepository.save(user); // <--- this will store the user to either the testing or the real DB, based on which data-source was initialized and injected in this class.
}
} If anyone is looking for a concrete working example, here's a commit I made in a test project that showcases exactly what I described above. It includes CRUD tests for a specific entity. Now, while this worked for me, I am not really sure how this could make it to the documentation. If anyone has any pointers, please share. |
Thanks |
Also spent quite an amount of time on this, here's how we did it: Repo file
|
Is there anyway to do this without a DI library? I need to mock my actual datasource for unit testing purposes. Despite typeDI library being really beneficial, it's not being fully maintained and it may cause vulnerabilities in the project I'm working on so I have to avoid it. |
Try this: Create a file called connection.ts somewhere in your project: import { IMemoryDb, newDb } from 'pg-mem'
import { DataSource } from 'typeorm'
type FakeDbResponse = {
db: IMemoryDb
dataSource: DataSource
}
export const makeFakeDb = async (entities?: any[]): Promise<FakeDbResponse> => {
const db = newDb({
autoCreateForeignKeyIndices: true
})
db.public.registerFunction({
implementation: () => 'test',
name: 'current_database'
})
const dataSource = await db.adapters.createTypeormDataSource({
type: 'postgres',
entities: entities ?? ['........'] // Your entities folder here
})
await dataSource.initialize()
await dataSource.synchronize()
return { db, dataSource }
} Then in the tests: import { YourEntity } from 'YOUR_ENTITIES_FOLDER' // [Replace here]
import { makeFakeDb } from 'connection.ts'
import { IBackup } from 'pg-mem'
import { DataSource, Repository } from 'typeorm'
describe('PgUserAccountRepository', () => {
let pgUserRepo: Repository<YourEntity>
let backup: IBackup
let dataSource: DataSource
beforeAll(async () => {
const fakeDb = await makeFakeDb([YourEntity])
dataSource = fakeDb.dataSource
backup = fakeDb.db.backup()
pgUserRepo = dataSource.getRepository(YourEntity)
})
afterAll(async () => {
await dataSource.destroy()
})
beforeEach(() => {
backup.restore()
})
it('should ... if email exists', async () => {
await pgUserRepo.save({ email: 'any_email' })
const account = await = someService.load({ email: 'any_email' })
expect(account).toEqual({ id: '1' })
})
}) I really hope that answer helps you |
The simpler way around it is to create a util that would handle switching the data source between testing and development. Something like this.
Then you can just do You can check out this repo for more info. |
Documentation Issue
What was unclear or otherwise insufficient?
According to this post, as well as the many others on the internet, testing with Jest is based on creating connections with
createConnection
and using theormconfig.js
. While I did not test this myself, it does seem to work.However, recently, the
createConnection
was deprecated and replaced by data-source. I haven't been able to find any documentation about how this works with Jest, nor was I able to make it work after spending some time on it.I've starting with the indications in the documentation and went with something like this
The issue I am facing is that I use the repositories pattern and everything related to the DB works like this (with
AppDataSource
)Now, I am using Jest to initialize and drop my test database
However, the tests do not work. I guess I need to find out a way to make use of the correct data-source in the main repositories and services. As in, find a way to inject whichever data-source I need from a central place.
I'm pretty sure this is not a bug, but either an error in my understanding, or in my approach. I believe an update to the documentation with a basic test would help a lot.
Recommended Fix
Having an example of running a basic test with Jest using a test DB would help a lot.
Additional Context
Are you willing to resolve this issue by submitting a Pull Request?
The text was updated successfully, but these errors were encountered: