This seems to work correctly in vitest:
main.ts
import { NestFactory } from '@nestjs/core';
import { OgmaService } from '@ogma/nestjs-module';
import { RootModule } from '@unteris/server/root';
import { request, spec } from 'pactum';
import { describe, beforeAll } from 'vitest';
import { csrfTest } from './tests/csrf';
describe('Unteris E2E test suite', () => {
beforeAll(async () => {
const app = await NestFactory.create(RootModule, { bufferLogs: true });
app.useLogger(app.get(OgmaService));
await app.listen(0);
const reqURL = await app.getUrl();
request.setBaseUrl(reqURL.replace('[::1]', 'localhost'));
return async () => {
await app.close();
};
});
csrfTest();
});
tests/csrf.ts'
import { parse } from 'lightcookie';
import { spec } from 'pactum';
import { describe, expect, test } from 'vitest';
export const csrfTest = () => {
return describe('CSRF Tests', () => {
test('CSRF Testing', async () => {
await spec()
.get('/csrf')
.expectStatus(200)
.expectJsonLike({ csrfToken: /\w+/ })
.expect(({ res }) => {
const cookies = res.headers['set-cookie'];
if (!cookies || cookies.length === 0) {
throw new Error('Received no cookies from the server');
}
cookies.forEach((cookie) => {
const parsed = parse(cookie);
expect(
['sessionId', 'refreshId'].some((cookieName) => {
return cookieName in parsed;
})
);
});
})
.stores((_req, res) => {
const { csrfToken } = res.body;
const cookies = res.headers['set-cookie'];
if (!cookies || cookies.length === 0) {
throw new Error('Received no cookies from the server');
}
const sessionId = cookies
.map((c) => parse(c))
.find((cookie) => 'sessionId' in cookie)?.sessionId;
const refreshId = cookies
.map((c) => parse(c))
.find((cookie) => 'refreshId' in cookie)?.refreshId;
return {
csrfToken,
sessionId,
refreshId,
};
})
.toss();
await spec()
.post('/csrf/verify')
.withHeaders('X-UNTERIS-CSRF-PROTECTION', '$S{csrfToken}')
.withCookies('sessionId', '$S{sessionId}')
.expectStatus(201)
.expectJson({ success: true })
.toss();
});
});
};
Now, I am using pactum so that I don't need direct access to the app instance, but I would bet that it's possible to pass that instance as necessary