mercredi 16 septembre 2020

Nest.js Jest cannot mock testing app but can mock testing controller

I have a Jest Nest.js controller test where I can stub the calls to the live database. It works fine.

I would like to have 'stubbed e2e' tests using nests HTTP Server (I am using supertest). However, when I import the AppModule I cannot seem to get jest to override anything.

Here is my working controller setup using stubbed classes.

describe('Working stubbed controller test', () => {
    let controller;

    beforeAll(async () => {
        const moduleFixture = await Test.createTestingModule({
            controllers: [MyController],
            providers: [
                {
                    provide: ObjectInjectionDependency,
                    useClass: ObjectInjectionDependency
                },
                {
                    provide: '@string/injection/dependency',
                    useClass: DbOjectMockIAmUsing
                },
                {
                    provide: '@another/string/injection/dependency',
                    useValue: '@another/string/injection/dependency',
                },
                {
                    provide: DbConnection,
                    useValue: {
                        selectOne: () => null,
                        selectAll: () => null
                    }
                }
            ]
        })
        .compile();

        controller = moduleFixture.get<MyController>(MyController)
    });

    it('/GET roots', async () => {
        const request = {
            method: "GET",
            params: {},
            query: {}
        }

        expect(
            await controller.all(request)
        ).toHaveProperty(
            'data'
        )
    });
});

Here is my unsuccessful attempt at incorporating stubbed classes along with the HTTP server using supertest. The stubbed classes are ignored.

describe('Bypassing stubs application test', () => {
    let app;
    let server;

    beforeAll(async () => {
        const moduleFixture = await Test.createTestingModule({
            imports: [AppModule],
            providers: [
                {
                    provide: ObjectInjectionDependency,
                    useClass: ObjectInjectionDependency
                },
                {
                    provide: '@string/injection/dependency',
                    useClass: DbOjectMockIAmUsing
                },
                {
                    provide: '@another/string/injection/dependency',
                    useValue: '@another/string/injection/dependency',
                },
                {
                    provide: DbConnection,
                    useValue: {
                        selectOne: () => null,
                        selectAll: () => null
                    }
                }
            ]
        })
        .compile();

        app = moduleFixture.createNestApplication();
        server = app.getHttpServer()
        await app.init();
    });

    it('/GET roots', async () => {
        expect(
            await request(server).get('/myEndpoint')
        ).toMatchObject({
            'statusCode': 200
        })
    });
});

I tried using the overrideProvider() methods but they didn't work either

const moduleFixture = await Test.createTestingModule({
    imports: [AppModule]
})
.overrideProvider(ObjectInjectionDependency)
    .useClass(ObjectInjectionDependency)
.overrideProvider('@string/injection/dependency')
    .useClass(DbOjectMockIAmUsing)
.overrideProvider('@another/string/injection/dependency')
    .useValue('@another/string/injection/dependency')
.overrideProvider(DbConnection)
    .useValue({
        selectOne: () => null,
        selectAll: () => null
    })
.compile() 

I also tried using Jest to override the classes

Jest.mock('@path/to/dbconnection', () => {
    selectOne: () => null,
    selectAll: () => null
}))

All didn't seem to have any effect.

I tried spyOn()

jest.spyOn(DbConnection, 'selectOne').mockImplementation(() => null);
jest.spyOn(DbConnection, 'selectAll').mockImplementation(() => null);

but I seem to get a strange error

No overload matches this call.
  Overload 1 of 4, '(object: typeof DbConnection, method: never): SpyInstance<never, never>', gave the following error.
    Argument of type 'string' is not assignable to parameter of type 'never'.
  Overload 2 of 4, '(object: typeof DbConnection, method: never): SpyInstance<never, never>', gave the following error.
    Argument of type 'string' is not assignable to parameter of type 'never'.ts(2769)

I understand that testing the controller is 'good enough' but I am still curious what I am doing wrong, as I am sure I will find a use case for this testing method in future.

Aucun commentaire:

Enregistrer un commentaire