omnivore/packages/api/test/resolvers/features.test.ts

204 lines
4.9 KiB
TypeScript
Raw Permalink Normal View History

2022-11-09 09:35:54 +00:00
import { expect } from 'chai'
import * as jwt from 'jsonwebtoken'
import 'mocha'
2022-11-09 09:35:54 +00:00
import sinon, { SinonFakeTimers } from 'sinon'
import { User } from '../../src/entity/user'
2022-11-09 09:35:54 +00:00
import { env } from '../../src/env'
2023-09-07 04:35:05 +00:00
import { userRepository } from '../../src/repository/user'
2024-03-23 08:40:01 +00:00
import {
createFeature,
createFeatures,
deleteFeature,
} from '../../src/services/features'
import { deleteUser, deleteUsers } from '../../src/services/user'
2023-09-07 04:35:05 +00:00
import { createTestUser } from '../db'
import { graphqlRequest, request } from '../util'
2022-11-09 09:35:54 +00:00
describe('features resolvers', () => {
2022-11-09 09:35:54 +00:00
let loginUser: User
let authToken: string
before(async () => {
// create test user and login
loginUser = await createTestUser('loginUser')
const res = await request
.post('/local/debug/fake-user-login')
.send({ fakeEmail: loginUser.email })
2024-03-23 08:40:01 +00:00
authToken = res.body.authToken as string
2022-11-09 09:35:54 +00:00
})
after(async () => {
2023-09-07 04:35:05 +00:00
await deleteUser(loginUser.id)
2022-11-09 09:35:54 +00:00
})
describe('optInFeature API', () => {
2022-11-09 14:48:33 +00:00
const featureName = 'ultra-realistic-voice'
2022-11-09 09:35:54 +00:00
const now = new Date()
let clock: SinonFakeTimers
const query = (name: string) => `
mutation {
optInFeature(input: {
name: "${name}"
}) {
... on OptInFeatureSuccess {
feature {
name
grantedAt
token
}
}
... on OptInFeatureError {
errorCodes
}
}
}
`
2022-11-09 14:48:33 +00:00
before(() => {
console.log('opting in to feature')
2022-11-09 10:14:15 +00:00
// mock date and ignore milliseconds
clock = sinon.useFakeTimers(now.setSeconds(now.getSeconds(), 0))
2022-11-09 09:35:54 +00:00
})
2022-11-09 14:48:33 +00:00
after(() => {
2022-11-09 09:35:54 +00:00
clock.restore()
})
2023-08-10 02:48:03 +00:00
context('when user is the first 1500 users', () => {
2022-11-09 09:35:54 +00:00
after(async () => {
// reset feature
2023-09-07 05:29:32 +00:00
await deleteFeature({ user: { id: loginUser.id } })
2022-11-09 09:35:54 +00:00
})
it('opts in to the feature', async () => {
2022-11-09 14:48:33 +00:00
const res = await graphqlRequest(query(featureName), authToken).expect(
200
)
2022-11-09 09:35:54 +00:00
const token = jwt.sign(
{
2022-11-09 14:48:33 +00:00
uid: loginUser.id,
featureName,
grantedAt: Date.now() / 1000,
2022-11-09 09:35:54 +00:00
},
2022-11-09 14:48:33 +00:00
env.server.jwtSecret,
{ expiresIn: '1y' }
2022-11-09 09:35:54 +00:00
)
expect(res.body.data.optInFeature).to.eql({
feature: {
2022-11-09 14:48:33 +00:00
name: featureName,
2022-11-09 10:14:15 +00:00
grantedAt: new Date().toISOString(),
2022-11-09 09:35:54 +00:00
token,
},
})
})
})
2023-08-10 02:48:03 +00:00
context('when user is not the first 1500 users', () => {
let users: User[]
2022-11-09 09:35:54 +00:00
before(async () => {
2023-08-10 02:48:03 +00:00
// create 1500 opt-in users
const usersToSave = Array.from(Array(1500).keys()).map((i) => {
2022-11-09 09:35:54 +00:00
return {
2022-11-10 13:32:49 +00:00
name: `opt-in-user-${i}`,
2022-11-09 09:35:54 +00:00
source: 'GOOGLE',
sourceUserId: `fake-user-id-user${i}`,
2025-09-24 10:37:39 +00:00
email: `opt-in-user-${i}@omnivore.work`,
2022-11-09 09:35:54 +00:00
username: `user${i}`,
bio: `i am user${i}`,
}
})
2023-09-07 04:35:05 +00:00
users = await userRepository.save(usersToSave)
2022-11-09 09:35:54 +00:00
const features = users.map((user) => {
return {
2023-09-07 05:29:32 +00:00
user,
2022-11-09 14:48:33 +00:00
name: featureName,
2022-11-09 10:14:15 +00:00
grantedAt: new Date(),
2022-11-09 09:35:54 +00:00
}
})
2023-09-07 05:29:32 +00:00
await createFeatures(features)
2022-11-09 09:35:54 +00:00
})
after(async () => {
// reset opt-in users
2024-03-23 08:40:01 +00:00
await deleteUsers(users.map((user) => user.id))
// reset feature
2023-09-07 05:29:32 +00:00
await deleteFeature({ name: featureName })
2022-11-09 09:35:54 +00:00
})
it('does not opt in to the feature', async () => {
2022-11-09 14:48:33 +00:00
const res = await graphqlRequest(query(featureName), authToken).expect(
200
)
2022-11-09 09:35:54 +00:00
const token = jwt.sign(
{
2022-11-09 14:48:33 +00:00
uid: loginUser.id,
featureName,
grantedAt: null,
2022-11-09 09:35:54 +00:00
},
2022-11-09 14:48:33 +00:00
env.server.jwtSecret,
{ expiresIn: '1y' }
2022-11-09 09:35:54 +00:00
)
expect(res.body.data.optInFeature).to.eql({
feature: {
2022-11-09 14:48:33 +00:00
name: featureName,
2022-11-09 09:35:54 +00:00
grantedAt: null,
token,
},
})
})
})
context('when user is already opted in', () => {
2024-05-15 08:23:52 +00:00
const grantedAt = new Date('2024-05-15')
2022-11-09 09:35:54 +00:00
before(async () => {
// opt in
2023-09-07 05:29:32 +00:00
await createFeature({
user: { id: loginUser.id },
name: featureName,
2024-05-15 08:23:52 +00:00
grantedAt,
2023-09-07 05:29:32 +00:00
})
2022-11-09 09:35:54 +00:00
})
after(async () => {
// reset feature
2023-09-07 05:29:32 +00:00
await deleteFeature({ user: { id: loginUser.id } })
2022-11-09 09:35:54 +00:00
})
it('returns the feature', async () => {
2022-11-09 14:48:33 +00:00
const res = await graphqlRequest(query(featureName), authToken).expect(
200
)
2022-11-09 09:35:54 +00:00
const token = jwt.sign(
{
2022-11-09 14:48:33 +00:00
uid: loginUser.id,
featureName,
2024-05-15 08:23:52 +00:00
grantedAt: grantedAt.getTime() / 1000,
2022-11-09 09:35:54 +00:00
},
2022-11-09 14:48:33 +00:00
env.server.jwtSecret,
{ expiresIn: '1y' }
2022-11-09 09:35:54 +00:00
)
expect(res.body.data.optInFeature).to.eql({
feature: {
2022-11-09 14:48:33 +00:00
name: featureName,
2024-05-15 08:23:52 +00:00
grantedAt: grantedAt.toISOString(),
2022-11-09 09:35:54 +00:00
token,
},
})
})
})
})
})