feat(api): setup jest in new api (#49709)

* feat(api): setup jest in new api

* feat: sample tests
This commit is contained in:
Tom
2023-03-16 10:03:40 -05:00
committed by GitHub
parent 32a2838714
commit 7aeb4ab76b
9 changed files with 819 additions and 50 deletions
+18
View File
@@ -0,0 +1,18 @@
import request, { Response } from 'supertest';
import { API_LOCATION as api } from './utils/env';
describe('GET /', () => {
let res: undefined | Response;
beforeAll(async () => {
res = await request(api).get('/');
});
test('have a 200 response', () => {
expect(res?.statusCode).toBe(200);
});
test('return { "hello": "world"}', () => {
expect(res?.body).toEqual({ hello: 'world' });
});
});
+11
View File
@@ -0,0 +1,11 @@
import type { Config } from 'jest';
const config: Config = {
verbose: true,
testRegex: '\\.test\\.ts$',
transform: {
'^.+\\.ts$': 'ts-jest'
}
};
export default config;
+11 -7
View File
@@ -8,14 +8,22 @@
"@fastify/middie": "8.1", "@fastify/middie": "8.1",
"@fastify/session": "^10.1.1", "@fastify/session": "^10.1.1",
"@prisma/client": "4.10.1", "@prisma/client": "4.10.1",
"connect-mongo": "4.6.0",
"@sinclair/typebox": "0.25.24", "@sinclair/typebox": "0.25.24",
"connect-mongo": "4.6.0",
"fastify": "4.14.1", "fastify": "4.14.1",
"fastify-auth0-verify": "^1.0.0", "fastify-auth0-verify": "^1.0.0",
"fastify-plugin": "^4.3.0", "fastify-plugin": "^4.3.0",
"nodemon": "2.0.21" "nodemon": "2.0.21"
}, },
"description": "The freeCodeCamp.org open-source codebase and curriculum", "description": "The freeCodeCamp.org open-source codebase and curriculum",
"devDependencies": {
"@fastify/type-provider-typebox": "2.4.0",
"@types/supertest": "2.0.12",
"jest": "29.5.0",
"prisma": "4.10.1",
"supertest": "6.3.3",
"ts-jest": "29.0.5"
},
"engines": { "engines": {
"node": ">=18", "node": ">=18",
"npm": ">=8" "npm": ">=8"
@@ -40,14 +48,10 @@
"scripts": { "scripts": {
"build": "tsc", "build": "tsc",
"develop": "nodemon index.ts", "develop": "nodemon index.ts",
"start": "NODE_ENV=production node index.js", "start": "NODE_ENV=production node index.ts",
"test": "node --test -r ts-node/register **/*.test.ts", "test": "node --test -r ts-node/register **/*.test.ts",
"prisma": "MONGOHQ_URL=mongodb://localhost:27017/freecodecamp?directConnection=true prisma", "prisma": "MONGOHQ_URL=mongodb://localhost:27017/freecodecamp?directConnection=true prisma",
"postinstall": "prisma generate" "postinstall": "prisma generate"
}, },
"version": "0.0.1", "version": "0.0.1"
"devDependencies": {
"prisma": "4.10.1",
"@fastify/type-provider-typebox": "2.4.0"
}
} }
+28 -30
View File
@@ -22,9 +22,6 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE. SOFTWARE.
*/ */
import assert from 'node:assert';
// eslint-disable-next-line import/no-unresolved
import { describe, it } from 'node:test';
import Fastify from 'fastify'; import Fastify from 'fastify';
import jwtAuthz from './fastify-jwt-authz'; import jwtAuthz from './fastify-jwt-authz';
@@ -34,13 +31,14 @@ interface ErrorResponse {
message: string; message: string;
} }
describe('fastify-jwt-authz', { only: true }, () => { describe('fastify-jwt-authz', () => {
it('should decorate request instance with jwtAuthz method', async () => { test('should decorate request instance with jwtAuthz method', async () => {
const fastify = Fastify(); const fastify = Fastify();
await fastify.register(jwtAuthz); await fastify.register(jwtAuthz);
fastify.get('/test', function (request) { fastify.get('/', req => {
assert(request.jwtAuthz); expect(req).toHaveProperty('jwtAuthz');
expect(req.jwtAuthz).toBeInstanceOf(Function);
return { foo: 'bar' }; return { foo: 'bar' };
}); });
@@ -50,13 +48,13 @@ describe('fastify-jwt-authz', { only: true }, () => {
const res = await fastify.inject({ const res = await fastify.inject({
method: 'GET', method: 'GET',
url: '/test' url: '/'
}); });
assert.strictEqual(res.statusCode, 200); expect(res.statusCode).toEqual(200);
}); });
it('should throw an error "Scopes cannot be empty" with an empty scopes parameter', async () => { test('should throw an error "Scopes cannot be empty" with an empty scopes parameter', async () => {
const fastify = Fastify(); const fastify = Fastify();
await fastify.register(jwtAuthz); await fastify.register(jwtAuthz);
@@ -82,11 +80,11 @@ describe('fastify-jwt-authz', { only: true }, () => {
}); });
const resData: ErrorResponse = res.json(); const resData: ErrorResponse = res.json();
assert.strictEqual(res.statusCode, 500); expect(res.statusCode).toEqual(500);
assert.strictEqual(resData.message, 'Scopes cannot be empty'); expect(resData.message).toEqual('Scopes cannot be empty');
}); });
it('should throw an error "request.user does not exist" non existing request.user', async () => { test('should throw an error "request.user does not exist" non existing request.user', async () => {
const fastify = Fastify(); const fastify = Fastify();
await fastify.register(jwtAuthz); await fastify.register(jwtAuthz);
@@ -112,11 +110,11 @@ describe('fastify-jwt-authz', { only: true }, () => {
}); });
const resData: ErrorResponse = res.json(); const resData: ErrorResponse = res.json();
assert.strictEqual(res.statusCode, 500); expect(res.statusCode).toEqual(500);
assert.strictEqual(resData.message, 'request.user does not exist'); expect(resData.message).toEqual('request.user does not exist');
}); });
it('should throw an error "request.user.scope must be a string"', async () => { test('should throw an error "request.user.scope must be a string"', async () => {
const fastify = Fastify(); const fastify = Fastify();
await fastify.register(jwtAuthz); await fastify.register(jwtAuthz);
@@ -146,11 +144,11 @@ describe('fastify-jwt-authz', { only: true }, () => {
}); });
const resData: ErrorResponse = res.json(); const resData: ErrorResponse = res.json();
assert.strictEqual(res.statusCode, 500); expect(res.statusCode).toEqual(500);
assert.strictEqual(resData.message, 'request.user.scope must be a string'); expect(resData.message).toEqual('request.user.scope must be a string');
}); });
it('should throw an error "Insufficient scope"', async () => { test('should throw an error "Insufficient scope"', async () => {
const fastify = Fastify(); const fastify = Fastify();
await fastify.register(jwtAuthz); await fastify.register(jwtAuthz);
@@ -180,11 +178,11 @@ describe('fastify-jwt-authz', { only: true }, () => {
}); });
const resData: ErrorResponse = res.json(); const resData: ErrorResponse = res.json();
assert.strictEqual(res.statusCode, 500); expect(res.statusCode).toEqual(500);
assert.strictEqual(resData.message, 'Insufficient scope'); expect(resData.message).toEqual('Insufficient scope');
}); });
it('should verify user scope', async () => { test('should verify user scope', async () => {
const fastify = Fastify(); const fastify = Fastify();
await fastify.register(jwtAuthz); await fastify.register(jwtAuthz);
@@ -215,11 +213,11 @@ describe('fastify-jwt-authz', { only: true }, () => {
const resData: { foo: string } = res.json(); const resData: { foo: string } = res.json();
assert.strictEqual(res.statusCode, 200); expect(res.statusCode).toEqual(200);
assert.strictEqual(resData.foo, 'bar'); expect(resData.foo).toEqual('bar');
}); });
it('should throw an error when there is no callback', async () => { test('should throw an error when there is no callback', async () => {
const fastify = Fastify(); const fastify = Fastify();
await fastify.register(jwtAuthz); await fastify.register(jwtAuthz);
@@ -251,11 +249,11 @@ describe('fastify-jwt-authz', { only: true }, () => {
}); });
const resData: ErrorResponse = res.json(); const resData: ErrorResponse = res.json();
assert.strictEqual(res.statusCode, 500); expect(res.statusCode).toEqual(500);
assert.strictEqual(resData.message, 'request.user.scope must be a string'); expect(resData.message).toEqual('request.user.scope must be a string');
}); });
it('should verify user scope when there is no callback', async () => { test('should verify user scope when there is no callback', async () => {
const fastify = Fastify(); const fastify = Fastify();
await fastify.register(jwtAuthz); await fastify.register(jwtAuthz);
@@ -286,7 +284,7 @@ describe('fastify-jwt-authz', { only: true }, () => {
}); });
const resData: { foo: string } = res.json(); const resData: { foo: string } = res.json();
assert.strictEqual(res.statusCode, 200); expect(res.statusCode).toEqual(200);
assert.strictEqual(resData.foo, 'bar'); expect(resData.foo).toEqual('bar');
}); });
}); });
+2
View File
@@ -21,6 +21,7 @@ if (error) {
assert.ok(process.env.NODE_ENV); assert.ok(process.env.NODE_ENV);
assert.ok(process.env.AUTH0_DOMAIN); assert.ok(process.env.AUTH0_DOMAIN);
assert.ok(process.env.AUTH0_AUDIENCE); assert.ok(process.env.AUTH0_AUDIENCE);
assert.ok(process.env.API_LOCATION);
assert.ok(process.env.SESSION_SECRET); assert.ok(process.env.SESSION_SECRET);
if (process.env.NODE_ENV !== 'development') { if (process.env.NODE_ENV !== 'development') {
@@ -35,4 +36,5 @@ export const NODE_ENV = process.env.NODE_ENV;
export const AUTH0_DOMAIN = process.env.AUTH0_DOMAIN; export const AUTH0_DOMAIN = process.env.AUTH0_DOMAIN;
export const AUTH0_AUDIENCE = process.env.AUTH0_AUDIENCE; export const AUTH0_AUDIENCE = process.env.AUTH0_AUDIENCE;
export const PORT = process.env.PORT || '3000'; export const PORT = process.env.PORT || '3000';
export const API_LOCATION = process.env.API_LOCATION;
export const SESSION_SECRET = process.env.SESSION_SECRET; export const SESSION_SECRET = process.env.SESSION_SECRET;
+9 -12
View File
@@ -1,18 +1,15 @@
import assert from 'node:assert';
// eslint-disable-next-line import/no-unresolved
import { describe, it } from 'node:test';
import { base64URLEncode, challenge, verifier } from '.'; import { base64URLEncode, challenge, verifier } from '.';
describe('utils', { only: true }, () => { describe('utils', () => {
it('base64URLEncode', () => { test('base64URLEncode', () => {
assert.strictEqual(base64URLEncode(Buffer.from('test')), 'dGVzdA'); expect(base64URLEncode(Buffer.from('test'))).toEqual('dGVzdA');
}); });
it('verifier', () => {
const v = verifier; test('verifier', () => {
assert.strictEqual(v.length, 43); expect(verifier).toHaveLength(43);
}); });
it('challenge', () => {
const c = challenge; test('challenge', () => {
assert.strictEqual(c.length, 43); expect(challenge).toHaveLength(43);
}); });
}); });
+1
View File
@@ -86,6 +86,7 @@
"test": "run-s create:* build:curriculum build-workers test:*", "test": "run-s create:* build:curriculum build-workers test:*",
"test:source": "jest", "test:source": "jest",
"test:curriculum": "cd ./curriculum && pnpm test", "test:curriculum": "cd ./curriculum && pnpm test",
"test-api": "cd api && jest",
"test-curriculum-full-output": "cd ./curriculum && pnpm run test:full-output", "test-curriculum-full-output": "cd ./curriculum && pnpm run test:full-output",
"test-client": "jest client", "test-client": "jest client",
"test-config": "jest config", "test-config": "jest config",
+733 -1
View File
File diff suppressed because it is too large Load Diff
+6
View File
@@ -69,3 +69,9 @@ PEER=stuff
DEBUG=true DEBUG=true
LOCAL_MOCK_AUTH=true LOCAL_MOCK_AUTH=true
CODESEE=false CODESEE=false
# ---------------------
# New API
# ---------------------
NODE_ENV=development
PORT=3000