Merge pull request #1314 from automatisch/get-user-test
feat: Implement getUser graphQL query test
This commit is contained in:
@@ -115,6 +115,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@automatisch/types": "^0.9.3",
|
||||
"@faker-js/faker": "^8.1.0",
|
||||
"@types/bcrypt": "^5.0.0",
|
||||
"@types/bull": "^3.15.8",
|
||||
"@types/cors": "^2.8.12",
|
||||
@@ -133,9 +134,11 @@
|
||||
"@types/pino": "^7.0.5",
|
||||
"@types/pluralize": "^0.0.30",
|
||||
"@types/showdown": "^2.0.1",
|
||||
"@types/supertest": "^2.0.14",
|
||||
"jest": "^29.7.0",
|
||||
"nodemon": "^2.0.13",
|
||||
"sinon": "^11.1.2",
|
||||
"supertest": "^6.3.3",
|
||||
"ts-jest": "^29.1.1",
|
||||
"ts-node": "^10.2.1",
|
||||
"ts-node-dev": "^1.1.8"
|
||||
|
@@ -1,6 +1,5 @@
|
||||
import User from '../../models/user';
|
||||
import jwt from 'jsonwebtoken';
|
||||
import appConfig from '../../config/app';
|
||||
import createAuthTokenByUserId from '../../helpers/create-auth-token-by-user-id';
|
||||
|
||||
type Params = {
|
||||
input: {
|
||||
@@ -9,18 +8,13 @@ type Params = {
|
||||
};
|
||||
};
|
||||
|
||||
const TOKEN_EXPIRES_IN = '14d';
|
||||
|
||||
const login = async (_parent: unknown, params: Params) => {
|
||||
const user = await User.query().findOne({
|
||||
email: params.input.email.toLowerCase(),
|
||||
});
|
||||
|
||||
if (user && (await user.login(params.input.password))) {
|
||||
const token = jwt.sign({ userId: user.id }, appConfig.appSecretKey, {
|
||||
expiresIn: TOKEN_EXPIRES_IN,
|
||||
});
|
||||
|
||||
const token = createAuthTokenByUserId(user.id);
|
||||
return { token, user };
|
||||
}
|
||||
|
||||
|
@@ -1,3 +1,161 @@
|
||||
test('adds 1 + 2 to equal 3', () => {
|
||||
expect(1 + 2).toBe(3);
|
||||
import request from 'supertest';
|
||||
import app from '../../app';
|
||||
import createAuthTokenByUserId from '../../helpers/create-auth-token-by-user-id';
|
||||
import Crypto from 'crypto';
|
||||
|
||||
describe('getUser', () => {
|
||||
it('should throw not authorized error for an unauthorized user', async () => {
|
||||
const invalidUserId = '123123123';
|
||||
|
||||
const query = `
|
||||
query {
|
||||
getUser(id: "${invalidUserId}") {
|
||||
id
|
||||
email
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const response = await request(app)
|
||||
.post('/graphql')
|
||||
.set('Authorization', 'invalid-token')
|
||||
.send({ query })
|
||||
.expect(200);
|
||||
|
||||
expect(response.body.errors).toBeDefined();
|
||||
expect(response.body.errors[0].message).toEqual('Not Authorised!');
|
||||
});
|
||||
|
||||
describe('with authorized user', () => {
|
||||
it('should return user data for a valid user id', async () => {
|
||||
const [role] = await knex
|
||||
.table('roles')
|
||||
.insert({
|
||||
key: 'sample',
|
||||
name: 'sample',
|
||||
})
|
||||
.returning('*');
|
||||
|
||||
await knex.table('permissions').insert({
|
||||
action: 'read',
|
||||
subject: 'User',
|
||||
role_id: role.id,
|
||||
});
|
||||
|
||||
const [currentUser] = await knex
|
||||
.table('users')
|
||||
.insert({
|
||||
full_name: 'Test User',
|
||||
email: 'sample@sample.com',
|
||||
password: 'secret',
|
||||
role_id: role.id,
|
||||
})
|
||||
.returning('*');
|
||||
|
||||
const [anotherUser] = await global.knex
|
||||
.table('users')
|
||||
.insert({
|
||||
full_name: 'Another User',
|
||||
email: 'another@sample.com',
|
||||
password: 'secret',
|
||||
role_id: role.id,
|
||||
})
|
||||
.returning('*');
|
||||
|
||||
const query = `
|
||||
query {
|
||||
getUser(id: "${anotherUser.id}") {
|
||||
id
|
||||
email
|
||||
fullName
|
||||
email
|
||||
createdAt
|
||||
updatedAt
|
||||
role {
|
||||
id
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const token = createAuthTokenByUserId(currentUser.id);
|
||||
|
||||
const response = await request(app)
|
||||
.post('/graphql')
|
||||
.set('Authorization', `${token}`)
|
||||
.send({ query })
|
||||
.expect(200);
|
||||
|
||||
const expectedResponsePayload = {
|
||||
data: {
|
||||
getUser: {
|
||||
createdAt: anotherUser.created_at.getTime().toString(),
|
||||
email: anotherUser.email,
|
||||
fullName: anotherUser.full_name,
|
||||
id: anotherUser.id,
|
||||
role: { id: role.id, name: role.name },
|
||||
updatedAt: anotherUser.updated_at.getTime().toString(),
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
expect(response.body).toEqual(expectedResponsePayload);
|
||||
});
|
||||
|
||||
it('should return not found for invalid user id', async () => {
|
||||
const [role] = await knex('roles')
|
||||
.insert({
|
||||
key: 'sample',
|
||||
name: 'sample',
|
||||
})
|
||||
.returning('*');
|
||||
|
||||
await knex.table('permissions').insert({
|
||||
action: 'read',
|
||||
subject: 'User',
|
||||
role_id: role.id,
|
||||
});
|
||||
|
||||
const [currentUser] = await knex
|
||||
.table('users')
|
||||
.insert({
|
||||
full_name: 'Test User',
|
||||
email: 'sample@sample.com',
|
||||
password: 'secret',
|
||||
role_id: role.id,
|
||||
})
|
||||
.returning('*');
|
||||
|
||||
const invalidUserId = Crypto.randomUUID();
|
||||
|
||||
const query = `
|
||||
query {
|
||||
getUser(id: "${invalidUserId}") {
|
||||
id
|
||||
email
|
||||
fullName
|
||||
email
|
||||
createdAt
|
||||
updatedAt
|
||||
role {
|
||||
id
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
const token = createAuthTokenByUserId(currentUser.id);
|
||||
|
||||
const response = await request(app)
|
||||
.post('/graphql')
|
||||
.set('Authorization', `${token}`)
|
||||
.send({ query })
|
||||
.expect(200);
|
||||
|
||||
expect(response.body.errors).toBeDefined();
|
||||
expect(response.body.errors[0].message).toEqual('NotFoundError');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
4
packages/backend/src/types/global.d.ts
vendored
4
packages/backend/src/types/global.d.ts
vendored
@@ -3,6 +3,8 @@ import { Knex } from 'knex';
|
||||
declare global {
|
||||
declare namespace globalThis {
|
||||
// eslint-disable-next-line no-var
|
||||
var knex: Knex;
|
||||
var knexInstance: Knex;
|
||||
// eslint-disable-next-line no-var
|
||||
var knex: Knex.Transaction;
|
||||
}
|
||||
}
|
||||
|
@@ -1,17 +1,27 @@
|
||||
import { Model } from 'objection';
|
||||
import { client as knex } from '../../src/config/database';
|
||||
import logger from '../../src/helpers/logger';
|
||||
|
||||
global.beforeAll(async () => {
|
||||
global.knex = knex;
|
||||
global.knexInstance = knex;
|
||||
global.knex = null;
|
||||
logger.silent = true;
|
||||
});
|
||||
|
||||
global.beforeEach(async function () {
|
||||
this.transaction = await global.knex.transaction();
|
||||
global.beforeEach(async () => {
|
||||
// It's assigned as global.knex for the convenience even though
|
||||
// it's a transaction. It's rolled back after each test.
|
||||
// by assigning to knex, we can use it as knex.table('example') in tests files.
|
||||
global.knex = await knex.transaction();
|
||||
Model.knex(global.knex);
|
||||
});
|
||||
|
||||
global.afterEach(async function () {
|
||||
await this.transaction.rollback();
|
||||
global.afterEach(async () => {
|
||||
await global.knex.rollback();
|
||||
Model.knex(knex);
|
||||
});
|
||||
|
||||
global.afterAll(async () => {
|
||||
global.knex.destroy();
|
||||
global.knexInstance.destroy();
|
||||
logger.silent = false;
|
||||
});
|
||||
|
103
yarn.lock
103
yarn.lock
@@ -1678,6 +1678,11 @@
|
||||
minimatch "^3.0.4"
|
||||
strip-json-comments "^3.1.1"
|
||||
|
||||
"@faker-js/faker@^8.1.0":
|
||||
version "8.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@faker-js/faker/-/faker-8.1.0.tgz#e14896f1c57af2495e341dc4c7bf04125c8aeafd"
|
||||
integrity sha512-38DT60rumHfBYynif3lmtxMqMqmsOQIxQgEuPZxCk2yUYN0eqWpTACgxi0VpidvsJB8CRxCpvP7B3anK85FjtQ==
|
||||
|
||||
"@formatjs/ecma402-abstract@1.11.1":
|
||||
version "1.11.1"
|
||||
resolved "https://registry.npmjs.org/@formatjs/ecma402-abstract/-/ecma402-abstract-1.11.1.tgz"
|
||||
@@ -4037,6 +4042,11 @@
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/cookiejar@*":
|
||||
version "2.1.2"
|
||||
resolved "https://registry.yarnpkg.com/@types/cookiejar/-/cookiejar-2.1.2.tgz#66ad9331f63fe8a3d3d9d8c6e3906dd10f6446e8"
|
||||
integrity sha512-t73xJJrvdTjXrn4jLS9VSGRbz0nUY3cl2DMGDU48lKl+HR9dbbjW2A9r3g40VA++mQpy6uuHg33gy7du2BKpog==
|
||||
|
||||
"@types/cors@^2.8.12":
|
||||
version "2.8.12"
|
||||
resolved "https://registry.npmjs.org/@types/cors/-/cors-2.8.12.tgz"
|
||||
@@ -4587,6 +4597,21 @@
|
||||
resolved "https://registry.npmjs.org/@types/strip-json-comments/-/strip-json-comments-0.0.30.tgz"
|
||||
integrity sha512-7NQmHra/JILCd1QqpSzl8+mJRc8ZHz3uDm8YV1Ks9IhK0epEiTw8aIErbvH9PI+6XbqhyIQy3462nEsn7UVzjQ==
|
||||
|
||||
"@types/superagent@*":
|
||||
version "4.1.19"
|
||||
resolved "https://registry.yarnpkg.com/@types/superagent/-/superagent-4.1.19.tgz#33f4fa460fb9e79e5e47a96731725141c667acd0"
|
||||
integrity sha512-McM1mlc7PBZpCaw0fw/36uFqo0YeA6m8JqoyE4OfqXsZCIg0hPP2xdE6FM7r6fdprDZHlJwDpydUj1R++93hCA==
|
||||
dependencies:
|
||||
"@types/cookiejar" "*"
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/supertest@^2.0.14":
|
||||
version "2.0.14"
|
||||
resolved "https://registry.yarnpkg.com/@types/supertest/-/supertest-2.0.14.tgz#e8fb6f6feed58a0dd5c2036227865dfa6ff7411d"
|
||||
integrity sha512-Q900DeeHNFF3ZYYepf/EyJfZDA2JrnWLaSQ0YNV7+2GTo8IlJzauEnDGhya+hauncpBYTYGpVHwGdssJeAQ7eA==
|
||||
dependencies:
|
||||
"@types/superagent" "*"
|
||||
|
||||
"@types/testing-library__jest-dom@^5.9.1":
|
||||
version "5.14.2"
|
||||
resolved "https://registry.npmjs.org/@types/testing-library__jest-dom/-/testing-library__jest-dom-5.14.2.tgz"
|
||||
@@ -6879,6 +6904,11 @@ compare-versions@^4.1.3:
|
||||
resolved "https://registry.npmjs.org/compare-versions/-/compare-versions-4.1.3.tgz"
|
||||
integrity sha512-WQfnbDcrYnGr55UwbxKiQKASnTtNnaAWVi8jZyy8NTpVAXWACSne8lMD1iaIo9AiU6mnuLvSVshCzewVuWxHUg==
|
||||
|
||||
component-emitter@^1.3.0:
|
||||
version "1.3.0"
|
||||
resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0"
|
||||
integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==
|
||||
|
||||
component-type@^1.2.1:
|
||||
version "1.2.1"
|
||||
resolved "https://registry.npmjs.org/component-type/-/component-type-1.2.1.tgz"
|
||||
@@ -7109,6 +7139,11 @@ cookie@0.5.0:
|
||||
resolved "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz"
|
||||
integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==
|
||||
|
||||
cookiejar@^2.1.4:
|
||||
version "2.1.4"
|
||||
resolved "https://registry.yarnpkg.com/cookiejar/-/cookiejar-2.1.4.tgz#ee669c1fea2cf42dc31585469d193fef0d65771b"
|
||||
integrity sha512-LDx6oHrK+PhzLKJU9j5S7/Y3jM/mUHvD/DeI1WQmJn652iPC5Y4TBzC9l+5OMOXlyTTA+SmVUPm0HQUwpD5Jqw==
|
||||
|
||||
copyfiles@^2.4.1:
|
||||
version "2.4.1"
|
||||
resolved "https://registry.npmjs.org/copyfiles/-/copyfiles-2.4.1.tgz"
|
||||
@@ -7768,6 +7803,14 @@ dezalgo@^1.0.0:
|
||||
asap "^2.0.0"
|
||||
wrappy "1"
|
||||
|
||||
dezalgo@^1.0.4:
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/dezalgo/-/dezalgo-1.0.4.tgz#751235260469084c132157dfa857f386d4c33d81"
|
||||
integrity sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==
|
||||
dependencies:
|
||||
asap "^2.0.0"
|
||||
wrappy "1"
|
||||
|
||||
didyoumean@^1.2.2:
|
||||
version "1.2.2"
|
||||
resolved "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz"
|
||||
@@ -9080,6 +9123,11 @@ fast-redact@^3.0.0:
|
||||
resolved "https://registry.npmjs.org/fast-redact/-/fast-redact-3.0.2.tgz"
|
||||
integrity sha512-YN+CYfCVRVMUZOUPeinHNKgytM1wPI/C/UCLEi56EsY2dwwvI00kIJHJoI7pMVqGoMew8SMZ2SSfHKHULHXDsg==
|
||||
|
||||
fast-safe-stringify@^2.1.1:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz#c406a83b6e70d9e35ce3b30a81141df30aeba884"
|
||||
integrity sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==
|
||||
|
||||
fast-xml-parser@^4.0.11:
|
||||
version "4.2.5"
|
||||
resolved "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.2.5.tgz"
|
||||
@@ -9317,6 +9365,15 @@ form-data@^3.0.0:
|
||||
combined-stream "^1.0.8"
|
||||
mime-types "^2.1.12"
|
||||
|
||||
form-data@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452"
|
||||
integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==
|
||||
dependencies:
|
||||
asynckit "^0.4.0"
|
||||
combined-stream "^1.0.8"
|
||||
mime-types "^2.1.12"
|
||||
|
||||
form-data@~2.3.2:
|
||||
version "2.3.3"
|
||||
resolved "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz"
|
||||
@@ -9326,6 +9383,16 @@ form-data@~2.3.2:
|
||||
combined-stream "^1.0.6"
|
||||
mime-types "^2.1.12"
|
||||
|
||||
formidable@^2.1.2:
|
||||
version "2.1.2"
|
||||
resolved "https://registry.yarnpkg.com/formidable/-/formidable-2.1.2.tgz#fa973a2bec150e4ce7cac15589d7a25fc30ebd89"
|
||||
integrity sha512-CM3GuJ57US06mlpQ47YcunuUZ9jpm8Vx+P2CGt2j7HpgkKZO/DJYQ0Bobim8G6PFQmK5lOqOOdUXboU+h73A4g==
|
||||
dependencies:
|
||||
dezalgo "^1.0.4"
|
||||
hexoid "^1.0.0"
|
||||
once "^1.4.0"
|
||||
qs "^6.11.0"
|
||||
|
||||
forwarded@0.2.0:
|
||||
version "0.2.0"
|
||||
resolved "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz"
|
||||
@@ -9916,6 +9983,11 @@ he@1.2.0, he@^1.2.0:
|
||||
resolved "https://registry.npmjs.org/he/-/he-1.2.0.tgz"
|
||||
integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==
|
||||
|
||||
hexoid@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/hexoid/-/hexoid-1.0.0.tgz#ad10c6573fb907de23d9ec63a711267d9dc9bc18"
|
||||
integrity sha512-QFLV0taWQOZtvIRIAdBChesmogZrtuXvVWsFHZTk2SU+anspqZ2vMnoLg7IE1+Uk16N19APic1BuF8bC8c2m5g==
|
||||
|
||||
history@^5.2.0:
|
||||
version "5.2.0"
|
||||
resolved "https://registry.npmjs.org/history/-/history-5.2.0.tgz"
|
||||
@@ -12536,7 +12608,7 @@ merge2@^1.2.3, merge2@^1.3.0, merge2@^1.4.1:
|
||||
resolved "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz"
|
||||
integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==
|
||||
|
||||
methods@~1.1.2:
|
||||
methods@^1.1.2, methods@~1.1.2:
|
||||
version "1.1.2"
|
||||
resolved "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz"
|
||||
integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=
|
||||
@@ -12578,6 +12650,11 @@ mime@1.6.0:
|
||||
resolved "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz"
|
||||
integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==
|
||||
|
||||
mime@2.6.0:
|
||||
version "2.6.0"
|
||||
resolved "https://registry.yarnpkg.com/mime/-/mime-2.6.0.tgz#a2a682a95cd4d0cb1d6257e28f83da7e35800367"
|
||||
integrity sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==
|
||||
|
||||
mimic-fn@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz"
|
||||
@@ -16812,6 +16889,30 @@ stylis@4.1.3:
|
||||
resolved "https://registry.npmjs.org/stylis/-/stylis-4.1.3.tgz"
|
||||
integrity sha512-GP6WDNWf+o403jrEp9c5jibKavrtLW+/qYGhFxFrG8maXhwTBI7gLLhiBb0o7uFccWN+EOS9aMO6cGHWAO07OA==
|
||||
|
||||
superagent@^8.0.5:
|
||||
version "8.1.2"
|
||||
resolved "https://registry.yarnpkg.com/superagent/-/superagent-8.1.2.tgz#03cb7da3ec8b32472c9d20f6c2a57c7f3765f30b"
|
||||
integrity sha512-6WTxW1EB6yCxV5VFOIPQruWGHqc3yI7hEmZK6h+pyk69Lk/Ut7rLUY6W/ONF2MjBuGjvmMiIpsrVJ2vjrHlslA==
|
||||
dependencies:
|
||||
component-emitter "^1.3.0"
|
||||
cookiejar "^2.1.4"
|
||||
debug "^4.3.4"
|
||||
fast-safe-stringify "^2.1.1"
|
||||
form-data "^4.0.0"
|
||||
formidable "^2.1.2"
|
||||
methods "^1.1.2"
|
||||
mime "2.6.0"
|
||||
qs "^6.11.0"
|
||||
semver "^7.3.8"
|
||||
|
||||
supertest@^6.3.3:
|
||||
version "6.3.3"
|
||||
resolved "https://registry.yarnpkg.com/supertest/-/supertest-6.3.3.tgz#42f4da199fee656106fd422c094cf6c9578141db"
|
||||
integrity sha512-EMCG6G8gDu5qEqRQ3JjjPs6+FYT1a7Hv5ApHvtSghmOFJYtsU5S+pSb6Y2EUeCEY3CmEL3mmQ8YWlPOzQomabA==
|
||||
dependencies:
|
||||
methods "^1.1.2"
|
||||
superagent "^8.0.5"
|
||||
|
||||
supports-color@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz"
|
||||
|
Reference in New Issue
Block a user