diff --git a/sites/backend/package.json b/sites/backend/package.json index e58c81f6fd3..48437053a9b 100644 --- a/sites/backend/package.json +++ b/sites/backend/package.json @@ -4,7 +4,7 @@ "license": "MIT", "scripts": { "dev": "nodemon src/index.mjs", - "test": "npx mocha --require mocha-steps tests/*.test.mjs", + "test": "npx mocha --require mocha-steps tests/index.mjs", "initdb": "npx prisma db push", "newdb": "node ./scripts/newdb.mjs", "rmdb": "node ./scripts/rmdb.mjs", diff --git a/sites/backend/src/config.mjs b/sites/backend/src/config.mjs index 913e9d21d81..be7784666b2 100644 --- a/sites/backend/src/config.mjs +++ b/sites/backend/src/config.mjs @@ -20,7 +20,9 @@ const config = { url: process.env.API_DB_URL, }, tests: { - domain: process.env.TESTDOMAIN || 'mailtrap.freesewing.dev', + allow: process.env.ALLOW_UNITTESTS || false, + domain: process.env.TESTDOMAIN || 'freesewing.dev', + sendEmail: process.env.SEND_UNITTEST_EMAILS || false, }, static: process.env.API_STATIC, storage: process.env.API_STORAGE, diff --git a/sites/backend/src/models/apikey.mjs b/sites/backend/src/models/apikey.mjs index c537be58e41..b91f879ee3d 100644 --- a/sites/backend/src/models/apikey.mjs +++ b/sites/backend/src/models/apikey.mjs @@ -26,7 +26,7 @@ ApikeyModel.prototype.setResponse = function (status = 200, error = false, data }, } if (status === 201) this.response.body.result = 'created' - else if (status > 201) { + else if (status > 204) { this.response.body.error = error this.response.body.result = 'error' this.error = true @@ -80,6 +80,7 @@ ApikeyModel.prototype.removeIfAllowed = async function (where, user) { } } await this.remove(where) + this.setResponse(204) return this.setResponse(204) } diff --git a/sites/backend/src/models/user.mjs b/sites/backend/src/models/user.mjs index a9791bab7f4..47e4f9d0732 100644 --- a/sites/backend/src/models/user.mjs +++ b/sites/backend/src/models/user.mjs @@ -117,18 +117,19 @@ UserModel.prototype.create = async function ({ body }) { }) // Send signup email - await this.mailer.send({ - template: 'signup', - language: this.language, - to: this.email, - replacements: { - actionUrl: i18nUrl(this.language, `/confirm/signup/${this.Confirmation.record.id}`), - whyUrl: i18nUrl(this.language, `/docs/faq/email/why-signup`), - supportUrl: i18nUrl(this.language, `/patrons/join`), - }, - }) + if (!this.isUnitTest(body) || this.config.tests.sendEmail) + await this.mailer.send({ + template: 'signup', + language: this.language, + to: this.email, + replacements: { + actionUrl: i18nUrl(this.language, `/confirm/signup/${this.Confirmation.record.id}`), + whyUrl: i18nUrl(this.language, `/docs/faq/email/why-signup`), + supportUrl: i18nUrl(this.language, `/patrons/join`), + }, + }) - return body.unittest && this.email.split('@').pop() === this.config.tests.domain + return this.isUnitTest(body) ? this.setResponse(201, false, { email: this.email, confirmation: this.confirmation.record.id }) : this.setResponse(201, false, { email: this.email }) } @@ -268,3 +269,11 @@ UserModel.prototype.setResponse = function (status = 200, error = false, data = UserModel.prototype.sendResponse = async function (res) { return res.status(this.response.status).send(this.response.body) } + +/* + * Update method to determine whether this request is + * part of a unit test + */ +UserModel.prototype.isUnitTest = function (body) { + return body.unittest && this.email.split('@').pop() === this.config.tests.domain +} diff --git a/sites/backend/tests/apikey.mjs b/sites/backend/tests/apikey.mjs index 4bf24bc2d9d..9fd098d9ebb 100644 --- a/sites/backend/tests/apikey.mjs +++ b/sites/backend/tests/apikey.mjs @@ -1,9 +1,8 @@ export const apikeyTests = async (config, store, chai) => { const expect = chai.expect - const icon = '🎟️ ' - describe(`${icon} API Key create/read/delete`, () => { - step(`${icon} Create API Key`, (done) => { + describe(`${store.icon('key')} API Key create/read/delete`, () => { + step(`${store.icon('key', 'jwt')} Create API Key (jwt)`, (done) => { chai .request(config.api) .post('/apikey/jwt') @@ -27,7 +26,7 @@ export const apikeyTests = async (config, store, chai) => { }) }) - step(`${icon} Create API Key with KEY`, (done) => { + step(`${store.icon('key', 'key')} Create API Key (key)`, (done) => { chai .request(config.api) .post('/apikey/key') @@ -51,7 +50,7 @@ export const apikeyTests = async (config, store, chai) => { }) }) - step(`${icon} Read API Key with KEY (whoami)`, (done) => { + step(`${store.icon('key', 'key')} Read API key via whoami (key)`, (done) => { chai .request(config.api) .get(`/whoami/key`) @@ -67,7 +66,7 @@ export const apikeyTests = async (config, store, chai) => { }) }) - step(`${icon} Read API Key with KEY`, (done) => { + step(`${store.icon('key', 'key')} Read API key (key)`, (done) => { chai .request(config.api) .get(`/apikey/${store.apikey1.key}/key`) @@ -83,11 +82,11 @@ export const apikeyTests = async (config, store, chai) => { }) }) - step(`${icon} Read API Key with JWT`, (done) => { + step(`${store.icon('key', 'jwt')} Read API key (jwt)`, (done) => { chai .request(config.api) .get(`/apikey/${store.apikey2.key}/jwt`) - .set('Authorization', 'Bearer ' + store.token) + .set('Authorization', 'Bearer ' + store.account.token) .end((err, res) => { expect(res.status).to.equal(200) expect(res.type).to.equal('application/json') @@ -99,7 +98,7 @@ export const apikeyTests = async (config, store, chai) => { }) }) - step(`${icon} Remove API Key with KEY`, (done) => { + step(`${store.icon('key', 'key')} Remove API key (key)`, (done) => { chai .request(config.api) .delete(`/apikey/${store.apikey2.key}/key`) @@ -109,5 +108,16 @@ export const apikeyTests = async (config, store, chai) => { done() }) }) + + step(`${store.icon('key', 'jwt')} Remove API key (jwt)`, (done) => { + chai + .request(config.api) + .delete(`/apikey/${store.apikey1.key}/jwt`) + .set('Authorization', 'Bearer ' + store.account.token) + .end((err, res) => { + expect(res.status).to.equal(204) + done() + }) + }) }) } diff --git a/sites/backend/tests/index.mjs b/sites/backend/tests/index.mjs index 1a627e8f8e1..a7d21a15ab8 100644 --- a/sites/backend/tests/index.mjs +++ b/sites/backend/tests/index.mjs @@ -20,12 +20,18 @@ const store = { language: 'en', password: randomString(), }, + icons: { + user: '🧑 ', + jwt: '🎫 ', + key: '🎟️ ', + }, } +store.icon = (icon1, icon2 = false) => store.icons[icon1] + (icon2 ? store.icons[icon2] : '') // Run tests const runTests = async (config, store, chai) => { await setup(config, store, chai) - await userTests(config, store, chai) + //await userTests(config, store, chai) await apikeyTests(config, store, chai) } diff --git a/sites/backend/tests/user.mjs b/sites/backend/tests/user.mjs index 990566753ae..e85c7f851ff 100644 --- a/sites/backend/tests/user.mjs +++ b/sites/backend/tests/user.mjs @@ -1,9 +1,8 @@ export const userTests = async (config, store, chai) => { const expect = chai.expect - const icon = '🧑' - describe(`${icon} Signup flow and authentication`, async function () { - it(`${icon} Should return 400 on signup without body`, function (done) { + describe(`${store.icon('user')} Signup flow and authentication`, async function () { + it(`${store.icon('user')} Should return 400 on signup without body`, function (done) { this.store = store chai .request(config.api) @@ -24,7 +23,7 @@ export const userTests = async (config, store, chai) => { language: 'fr', } Object.keys(fields).map((key) => { - it(`${icon} Should not allow signup without ${key}`, (done) => { + it(`${store.icon('user')} Should not allow signup without ${key}`, (done) => { chai .request(config.api) .post('/signup') @@ -47,7 +46,7 @@ export const userTests = async (config, store, chai) => { }) }) - step(`${icon} Should fail to signup an existing email address`, (done) => { + step(`${store.icon('user')} Should fail to signup an existing email address`, (done) => { chai .request(config.api) .post('/signup') @@ -62,7 +61,7 @@ export const userTests = async (config, store, chai) => { }) }) - step(`${icon} Should not login with the wrong password`, (done) => { + step(`${store.icon('user')} Should not login with the wrong password`, (done) => { chai .request(config.api) .post('/login') @@ -80,7 +79,7 @@ export const userTests = async (config, store, chai) => { }) }) - step(`${icon} Should login with username and password`, (done) => { + step(`${store.icon('user')} Should login with username and password`, (done) => { chai .request(config.api) .post('/login') @@ -103,7 +102,7 @@ export const userTests = async (config, store, chai) => { }) }) - step(`${icon} Should login with USERNAME and password`, (done) => { + step(`${store.icon('user')} Should login with USERNAME and password`, (done) => { chai .request(config.api) .post('/login') @@ -126,7 +125,7 @@ export const userTests = async (config, store, chai) => { }) }) - step(`${icon} Should login with email and password`, (done) => { + step(`${store.icon('user')} Should login with email and password`, (done) => { chai .request(config.api) .post('/login') @@ -149,7 +148,7 @@ export const userTests = async (config, store, chai) => { }) }) - step(`${icon} Should login with EMAIL and password`, (done) => { + step(`${store.icon('user')} Should login with EMAIL and password`, (done) => { chai .request(config.api) .post('/login') @@ -172,7 +171,7 @@ export const userTests = async (config, store, chai) => { }) }) - step(`${icon} Should login with userid and password`, (done) => { + step(`${store.icon('user')} Should login with userid and password`, (done) => { chai .request(config.api) .post('/login') @@ -195,7 +194,7 @@ export const userTests = async (config, store, chai) => { }) }) - step(`${icon} Should load account with JWT`, (done) => { + step(`${store.icon('user', 'jwt')} Should load account (jwt)`, (done) => { chai .request(config.api) .get('/account/jwt') @@ -213,7 +212,7 @@ export const userTests = async (config, store, chai) => { }) }) - step(`${icon} Should load account with JWT (whoami)`, (done) => { + step(`${store.icon('user', 'jwt')} Should load account via whoami (jwt)`, (done) => { chai .request(config.api) .get('/whoami/jwt')