mirror of
https://github.com/Ocelot-Social-Community/Ocelot-Social.git
synced 2025-12-12 23:35:58 +00:00
This is a side quest of #8558. The motivation is to be able to do dependency injection in the tests without overwriting global data. I saw the first merge conflict from #8551 and voila: It seems @Mogge could have used this already. refactor: follow @Mogge's review See: https://github.com/Ocelot-Social-Community/Ocelot-Social/pull/8603#pullrequestreview-2880714796 refactor: better test helper methods wip: continue refactoring wip: continue posts continue wip: continue groups continue registration registration continue messages continue observeposts continue categories continue posts in groups continue invite codes refactor: continue notificationsMiddleware continue statistics spec followed-users online-status mentions-in-groups posts-in-groups email spec finish all tests improve typescript missed one test remove one more reference of CONFIG eliminate one more global import of CONFIG fix language spec test fix two more test suites refactor: completely mock out 3rd part API request refactor test fixed user_management spec fixed more locatoin specs install types for jsonwebtoken one more fetchmock fixed one more suite fix one more spec yet another spec fix spec delete whitespaces remove beforeAll that the same as the default fix merge conflict fix e2e test refactor: use single callback function for `context` setup refactor: display logs from backend during CI Because why not? fix seeds fix login refactor: one unnecessary naming refactor: better editor support refactor: fail early Interestingly, I've had to destructure `context.user` in order to make typescript happy. Weird. refactor: undo changes to workflows - no effect We're running in `--detached` mode on CI, so I guess we won't be able to see the logs anyways. refactor: remove fetch from context after review See: refactor: found an easier way for required props Co-authored-by: Max <maxharz@gmail.com> Co-authored-by: Ulf Gebhardt <ulf.gebhardt@webcraft-media.de>
722 lines
22 KiB
TypeScript
722 lines
22 KiB
TypeScript
/* eslint-disable @typescript-eslint/no-unsafe-argument */
|
|
/* eslint-disable @typescript-eslint/await-thenable */
|
|
/* eslint-disable @typescript-eslint/no-unsafe-call */
|
|
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
|
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
|
import { Readable } from 'node:stream'
|
|
|
|
import { Upload } from 'graphql-upload/public/index'
|
|
|
|
import pubsubContext from '@context/pubsub'
|
|
import Factory, { cleanDatabase } from '@db/factories'
|
|
import { CreateMessage } from '@graphql/queries/CreateMessage'
|
|
import { createRoomMutation } from '@graphql/queries/createRoomMutation'
|
|
import { MarkMessagesAsSeen } from '@graphql/queries/MarkMessagesAsSeen'
|
|
import { Message } from '@graphql/queries/Message'
|
|
import { roomQuery } from '@graphql/queries/roomQuery'
|
|
import type { ApolloTestSetup } from '@root/test/helpers'
|
|
import { createApolloTestSetup } from '@root/test/helpers'
|
|
import type { Context } from '@src/context'
|
|
|
|
let authenticatedUser: Context['user']
|
|
const context = () => ({ authenticatedUser, pubsub })
|
|
let mutate: ApolloTestSetup['mutate']
|
|
let query: ApolloTestSetup['query']
|
|
let database: ApolloTestSetup['database']
|
|
let server: ApolloTestSetup['server']
|
|
let chattingUser, otherChattingUser, notChattingUser
|
|
|
|
const pubsub = pubsubContext()
|
|
const pubsubSpy = jest.spyOn(pubsub, 'publish')
|
|
|
|
beforeAll(async () => {
|
|
await cleanDatabase()
|
|
const apolloSetup = createApolloTestSetup({ context })
|
|
mutate = apolloSetup.mutate
|
|
query = apolloSetup.query
|
|
database = apolloSetup.database
|
|
server = apolloSetup.server
|
|
})
|
|
|
|
beforeEach(async () => {
|
|
await cleanDatabase()
|
|
})
|
|
|
|
afterAll(async () => {
|
|
await cleanDatabase()
|
|
void server.stop()
|
|
void database.driver.close()
|
|
database.neode.close()
|
|
})
|
|
|
|
describe('Message', () => {
|
|
let roomId: string
|
|
|
|
beforeEach(async () => {
|
|
;[chattingUser, otherChattingUser, notChattingUser] = await Promise.all([
|
|
Factory.build('user', {
|
|
id: 'chatting-user',
|
|
name: 'Chatting User',
|
|
}),
|
|
Factory.build('user', {
|
|
id: 'other-chatting-user',
|
|
name: 'Other Chatting User',
|
|
}),
|
|
Factory.build('user', {
|
|
id: 'not-chatting-user',
|
|
name: 'Not Chatting User',
|
|
}),
|
|
])
|
|
})
|
|
|
|
describe('create message', () => {
|
|
beforeEach(() => {
|
|
jest.clearAllMocks()
|
|
})
|
|
|
|
describe('unauthenticated', () => {
|
|
beforeAll(() => {
|
|
authenticatedUser = null
|
|
})
|
|
|
|
it('throws authorization error', async () => {
|
|
await expect(
|
|
mutate({
|
|
mutation: CreateMessage,
|
|
variables: {
|
|
roomId: 'some-id',
|
|
content: 'Some bla bla bla',
|
|
},
|
|
}),
|
|
).resolves.toMatchObject({
|
|
errors: [{ message: 'Not Authorized!' }],
|
|
})
|
|
})
|
|
})
|
|
|
|
describe('authenticated', () => {
|
|
beforeAll(async () => {
|
|
authenticatedUser = await chattingUser.toJson()
|
|
})
|
|
|
|
describe('room does not exist', () => {
|
|
it('returns null and does not publish subscription', async () => {
|
|
await expect(
|
|
mutate({
|
|
mutation: CreateMessage,
|
|
variables: {
|
|
roomId: 'some-id',
|
|
content: 'Some bla bla bla',
|
|
},
|
|
}),
|
|
).resolves.toMatchObject({
|
|
errors: undefined,
|
|
data: {
|
|
CreateMessage: null,
|
|
},
|
|
})
|
|
expect(pubsubSpy).not.toBeCalled()
|
|
})
|
|
})
|
|
|
|
describe('room exists', () => {
|
|
beforeEach(async () => {
|
|
authenticatedUser = await chattingUser.toJson()
|
|
const room = await mutate({
|
|
mutation: createRoomMutation(),
|
|
variables: {
|
|
userId: 'other-chatting-user',
|
|
},
|
|
})
|
|
roomId = (room.data as any).CreateRoom.id // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
})
|
|
|
|
describe('user chats in room', () => {
|
|
it('returns the message', async () => {
|
|
await expect(
|
|
mutate({
|
|
mutation: CreateMessage,
|
|
variables: {
|
|
roomId,
|
|
content: 'Some nice message to other chatting user',
|
|
},
|
|
}),
|
|
).resolves.toMatchObject({
|
|
errors: undefined,
|
|
data: {
|
|
CreateMessage: {
|
|
id: expect.any(String),
|
|
content: 'Some nice message to other chatting user',
|
|
senderId: 'chatting-user',
|
|
username: 'Chatting User',
|
|
avatar: expect.any(String),
|
|
date: expect.any(String),
|
|
saved: true,
|
|
distributed: false,
|
|
seen: false,
|
|
},
|
|
},
|
|
})
|
|
})
|
|
|
|
beforeEach(async () => {
|
|
await mutate({
|
|
mutation: CreateMessage,
|
|
variables: {
|
|
roomId,
|
|
content: 'Some nice message to other chatting user',
|
|
},
|
|
})
|
|
})
|
|
|
|
describe('room is updated as well', () => {
|
|
it('has last message set', async () => {
|
|
const result = await query({ query: roomQuery() })
|
|
await expect(result).toMatchObject({
|
|
errors: undefined,
|
|
data: {
|
|
Room: [
|
|
expect.objectContaining({
|
|
lastMessageAt: expect.any(String),
|
|
unreadCount: 0,
|
|
lastMessage: expect.objectContaining({
|
|
_id: result.data?.Room[0].lastMessage.id,
|
|
id: expect.any(String),
|
|
content: 'Some nice message to other chatting user',
|
|
senderId: 'chatting-user',
|
|
username: 'Chatting User',
|
|
avatar: expect.any(String),
|
|
date: expect.any(String),
|
|
saved: true,
|
|
distributed: false,
|
|
seen: false,
|
|
}),
|
|
}),
|
|
],
|
|
},
|
|
})
|
|
})
|
|
})
|
|
|
|
describe('unread count for other user', () => {
|
|
it('has unread count = 1', async () => {
|
|
authenticatedUser = await otherChattingUser.toJson()
|
|
await expect(query({ query: roomQuery() })).resolves.toMatchObject({
|
|
errors: undefined,
|
|
data: {
|
|
Room: [
|
|
expect.objectContaining({
|
|
lastMessageAt: expect.any(String),
|
|
unreadCount: 1,
|
|
lastMessage: expect.objectContaining({
|
|
_id: expect.any(String),
|
|
id: expect.any(String),
|
|
content: 'Some nice message to other chatting user',
|
|
senderId: 'chatting-user',
|
|
username: 'Chatting User',
|
|
avatar: expect.any(String),
|
|
date: expect.any(String),
|
|
saved: true,
|
|
distributed: false,
|
|
seen: false,
|
|
}),
|
|
}),
|
|
],
|
|
},
|
|
})
|
|
})
|
|
})
|
|
})
|
|
|
|
describe('user sends files in room', () => {
|
|
const file1 = Readable.from('file1')
|
|
const upload1 = new Upload()
|
|
upload1.resolve({
|
|
createReadStream: () => file1,
|
|
stream: file1,
|
|
filename: 'file1',
|
|
encoding: '7bit',
|
|
mimetype: 'application/json',
|
|
})
|
|
const file2 = Readable.from('file2')
|
|
const upload2 = new Upload()
|
|
upload2.resolve({
|
|
createReadStream: () => file2,
|
|
stream: file2,
|
|
filename: 'file2',
|
|
encoding: '7bit',
|
|
mimetype: 'image/png',
|
|
})
|
|
it('returns the message', async () => {
|
|
await expect(
|
|
mutate({
|
|
mutation: CreateMessage,
|
|
variables: {
|
|
roomId,
|
|
content: 'Some files for other chatting user',
|
|
files: [
|
|
{ upload: upload1, name: 'test1', type: 'application/json' },
|
|
{ upload: upload2, name: 'test2', type: 'image/png' },
|
|
],
|
|
},
|
|
}),
|
|
).resolves.toMatchObject({
|
|
errors: undefined,
|
|
data: {
|
|
CreateMessage: {
|
|
id: expect.any(String),
|
|
content: 'Some files for other chatting user',
|
|
senderId: 'chatting-user',
|
|
username: 'Chatting User',
|
|
avatar: expect.any(String),
|
|
date: expect.any(String),
|
|
saved: true,
|
|
distributed: false,
|
|
seen: false,
|
|
files: expect.arrayContaining([
|
|
{ name: 'test1', type: 'application/json', url: expect.any(String) },
|
|
{ name: 'test2', type: 'image/png', url: expect.any(String) },
|
|
]),
|
|
},
|
|
},
|
|
})
|
|
})
|
|
})
|
|
|
|
describe('user sends file, but upload goes wrong', () => {
|
|
const file1 = Readable.from('file1')
|
|
const upload1 = new Upload()
|
|
upload1.resolve({
|
|
createReadStream: () => file1,
|
|
stream: file1,
|
|
filename: 'file1',
|
|
encoding: '7bit',
|
|
mimetype: 'application/json',
|
|
})
|
|
const upload2 = new Upload()
|
|
upload2.resolve(new Error('Upload failed'))
|
|
|
|
it('no message is created', async () => {
|
|
await expect(
|
|
mutate({
|
|
mutation: CreateMessage,
|
|
variables: {
|
|
roomId,
|
|
content: 'A message which should not be created',
|
|
files: [
|
|
{ upload: upload1, name: 'test1', type: 'application/json' },
|
|
{ upload: upload2, name: 'test2', type: 'image/png' },
|
|
],
|
|
},
|
|
}),
|
|
).resolves.toMatchObject({
|
|
errors: {},
|
|
data: {
|
|
CreateMessage: null,
|
|
},
|
|
})
|
|
|
|
await expect(
|
|
query({
|
|
query: Message,
|
|
variables: {
|
|
roomId,
|
|
},
|
|
}),
|
|
).resolves.toMatchObject({
|
|
errors: undefined,
|
|
data: {
|
|
Message: [],
|
|
},
|
|
})
|
|
})
|
|
})
|
|
|
|
describe('user does not chat in room', () => {
|
|
beforeEach(async () => {
|
|
authenticatedUser = await notChattingUser.toJson()
|
|
})
|
|
|
|
it('returns null', async () => {
|
|
await expect(
|
|
mutate({
|
|
mutation: CreateMessage,
|
|
variables: {
|
|
roomId,
|
|
content: 'I have no access to this room!',
|
|
},
|
|
}),
|
|
).resolves.toMatchObject({
|
|
errors: undefined,
|
|
data: {
|
|
CreateMessage: null,
|
|
},
|
|
})
|
|
})
|
|
})
|
|
})
|
|
})
|
|
})
|
|
|
|
describe('message query', () => {
|
|
describe('unauthenticated', () => {
|
|
beforeAll(() => {
|
|
authenticatedUser = null
|
|
})
|
|
|
|
it('throws authorization error', async () => {
|
|
await expect(
|
|
query({
|
|
query: Message,
|
|
variables: {
|
|
roomId: 'some-id',
|
|
},
|
|
}),
|
|
).resolves.toMatchObject({
|
|
errors: [{ message: 'Not Authorized!' }],
|
|
})
|
|
})
|
|
})
|
|
|
|
describe('authenticated', () => {
|
|
beforeAll(async () => {
|
|
authenticatedUser = await otherChattingUser.toJson()
|
|
})
|
|
|
|
describe('room does not exists', () => {
|
|
it('returns null', async () => {
|
|
await expect(
|
|
query({
|
|
query: Message,
|
|
variables: {
|
|
roomId: 'some-id',
|
|
},
|
|
}),
|
|
).resolves.toMatchObject({
|
|
errors: undefined,
|
|
data: {
|
|
Message: [],
|
|
},
|
|
})
|
|
})
|
|
})
|
|
|
|
describe('room exists with authenticated user chatting', () => {
|
|
beforeEach(async () => {
|
|
authenticatedUser = await chattingUser.toJson()
|
|
const room = await mutate({
|
|
mutation: createRoomMutation(),
|
|
variables: {
|
|
userId: 'other-chatting-user',
|
|
},
|
|
})
|
|
roomId = (room.data as any).CreateRoom.id // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
|
|
await mutate({
|
|
mutation: CreateMessage,
|
|
variables: {
|
|
roomId,
|
|
content: 'Some nice message to other chatting user',
|
|
},
|
|
})
|
|
})
|
|
|
|
it('returns the messages', async () => {
|
|
const result = await query({
|
|
query: Message,
|
|
variables: {
|
|
roomId,
|
|
},
|
|
})
|
|
expect(result).toMatchObject({
|
|
errors: undefined,
|
|
data: {
|
|
Message: [
|
|
{
|
|
id: expect.any(String),
|
|
_id: result.data?.Message[0].id,
|
|
indexId: 0,
|
|
content: 'Some nice message to other chatting user',
|
|
senderId: 'chatting-user',
|
|
username: 'Chatting User',
|
|
avatar: expect.any(String),
|
|
date: expect.any(String),
|
|
saved: true,
|
|
distributed: false,
|
|
seen: false,
|
|
},
|
|
],
|
|
},
|
|
})
|
|
})
|
|
|
|
describe('more messages', () => {
|
|
beforeEach(async () => {
|
|
authenticatedUser = await otherChattingUser.toJson()
|
|
await mutate({
|
|
mutation: CreateMessage,
|
|
variables: {
|
|
roomId,
|
|
content: 'A nice response message to chatting user',
|
|
},
|
|
})
|
|
authenticatedUser = await chattingUser.toJson()
|
|
await mutate({
|
|
mutation: CreateMessage,
|
|
variables: {
|
|
roomId,
|
|
content: 'And another nice message to other chatting user',
|
|
},
|
|
})
|
|
})
|
|
|
|
it('returns the messages', async () => {
|
|
await expect(
|
|
query({
|
|
query: Message,
|
|
variables: {
|
|
roomId,
|
|
},
|
|
}),
|
|
).resolves.toMatchObject({
|
|
errors: undefined,
|
|
data: {
|
|
Message: [
|
|
expect.objectContaining({
|
|
id: expect.any(String),
|
|
indexId: 0,
|
|
content: 'Some nice message to other chatting user',
|
|
senderId: 'chatting-user',
|
|
username: 'Chatting User',
|
|
avatar: expect.any(String),
|
|
date: expect.any(String),
|
|
saved: true,
|
|
distributed: false,
|
|
seen: false,
|
|
}),
|
|
expect.objectContaining({
|
|
id: expect.any(String),
|
|
indexId: 1,
|
|
content: 'A nice response message to chatting user',
|
|
senderId: 'other-chatting-user',
|
|
username: 'Other Chatting User',
|
|
avatar: expect.any(String),
|
|
date: expect.any(String),
|
|
saved: true,
|
|
distributed: true,
|
|
seen: false,
|
|
}),
|
|
expect.objectContaining({
|
|
id: expect.any(String),
|
|
indexId: 2,
|
|
content: 'And another nice message to other chatting user',
|
|
senderId: 'chatting-user',
|
|
username: 'Chatting User',
|
|
avatar: expect.any(String),
|
|
date: expect.any(String),
|
|
saved: true,
|
|
distributed: false,
|
|
seen: false,
|
|
}),
|
|
],
|
|
},
|
|
})
|
|
})
|
|
|
|
it('returns the messages paginated', async () => {
|
|
await expect(
|
|
query({
|
|
query: Message,
|
|
variables: {
|
|
roomId,
|
|
first: 2,
|
|
offset: 0,
|
|
},
|
|
}),
|
|
).resolves.toMatchObject({
|
|
errors: undefined,
|
|
data: {
|
|
Message: [
|
|
expect.objectContaining({
|
|
id: expect.any(String),
|
|
indexId: 1,
|
|
content: 'A nice response message to chatting user',
|
|
senderId: 'other-chatting-user',
|
|
username: 'Other Chatting User',
|
|
avatar: expect.any(String),
|
|
date: expect.any(String),
|
|
}),
|
|
expect.objectContaining({
|
|
id: expect.any(String),
|
|
indexId: 2,
|
|
content: 'And another nice message to other chatting user',
|
|
senderId: 'chatting-user',
|
|
username: 'Chatting User',
|
|
avatar: expect.any(String),
|
|
date: expect.any(String),
|
|
}),
|
|
],
|
|
},
|
|
})
|
|
|
|
await expect(
|
|
query({
|
|
query: Message,
|
|
variables: {
|
|
roomId,
|
|
first: 2,
|
|
offset: 2,
|
|
},
|
|
}),
|
|
).resolves.toMatchObject({
|
|
errors: undefined,
|
|
data: {
|
|
Message: [
|
|
expect.objectContaining({
|
|
id: expect.any(String),
|
|
indexId: 0,
|
|
content: 'Some nice message to other chatting user',
|
|
senderId: 'chatting-user',
|
|
username: 'Chatting User',
|
|
avatar: expect.any(String),
|
|
date: expect.any(String),
|
|
}),
|
|
],
|
|
},
|
|
})
|
|
})
|
|
})
|
|
})
|
|
|
|
describe('room exists, authenticated user not in room', () => {
|
|
beforeAll(async () => {
|
|
authenticatedUser = await notChattingUser.toJson()
|
|
})
|
|
|
|
it('returns null', async () => {
|
|
await expect(
|
|
query({
|
|
query: Message,
|
|
variables: {
|
|
roomId,
|
|
},
|
|
}),
|
|
).resolves.toMatchObject({
|
|
errors: undefined,
|
|
data: {
|
|
Message: [],
|
|
},
|
|
})
|
|
})
|
|
})
|
|
})
|
|
})
|
|
|
|
describe('marks massges as seen', () => {
|
|
describe('unauthenticated', () => {
|
|
beforeAll(() => {
|
|
authenticatedUser = null
|
|
})
|
|
|
|
it('throws authorization error', async () => {
|
|
await expect(
|
|
mutate({
|
|
mutation: MarkMessagesAsSeen,
|
|
variables: {
|
|
messageIds: ['some-id'],
|
|
},
|
|
}),
|
|
).resolves.toMatchObject({
|
|
errors: [{ message: 'Not Authorized!' }],
|
|
})
|
|
})
|
|
})
|
|
|
|
describe('authenticated', () => {
|
|
const messageIds: string[] = []
|
|
beforeEach(async () => {
|
|
authenticatedUser = await chattingUser.toJson()
|
|
const room = await mutate({
|
|
mutation: createRoomMutation(),
|
|
variables: {
|
|
userId: 'other-chatting-user',
|
|
},
|
|
})
|
|
roomId = (room.data as any).CreateRoom.id // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
await mutate({
|
|
mutation: CreateMessage,
|
|
variables: {
|
|
roomId,
|
|
content: 'Some nice message to other chatting user',
|
|
},
|
|
})
|
|
authenticatedUser = await otherChattingUser.toJson()
|
|
await mutate({
|
|
mutation: CreateMessage,
|
|
variables: {
|
|
roomId,
|
|
content: 'A nice response message to chatting user',
|
|
},
|
|
})
|
|
authenticatedUser = await chattingUser.toJson()
|
|
await mutate({
|
|
mutation: CreateMessage,
|
|
variables: {
|
|
roomId,
|
|
content: 'And another nice message to other chatting user',
|
|
},
|
|
})
|
|
authenticatedUser = await otherChattingUser.toJson()
|
|
const msgs = await query({
|
|
query: Message,
|
|
variables: {
|
|
roomId,
|
|
},
|
|
})
|
|
msgs.data?.Message.forEach((m) => messageIds.push(m.id))
|
|
})
|
|
|
|
it('returns true', async () => {
|
|
await expect(
|
|
mutate({
|
|
mutation: MarkMessagesAsSeen,
|
|
variables: {
|
|
messageIds,
|
|
},
|
|
}),
|
|
).resolves.toMatchObject({
|
|
errors: undefined,
|
|
data: {
|
|
MarkMessagesAsSeen: true,
|
|
},
|
|
})
|
|
})
|
|
|
|
it('has seen prop set to true', async () => {
|
|
await mutate({
|
|
mutation: MarkMessagesAsSeen,
|
|
variables: {
|
|
messageIds,
|
|
},
|
|
})
|
|
await expect(
|
|
query({
|
|
query: Message,
|
|
variables: {
|
|
roomId,
|
|
},
|
|
}),
|
|
).resolves.toMatchObject({
|
|
data: {
|
|
Message: [
|
|
expect.objectContaining({ seen: true }),
|
|
expect.objectContaining({ seen: false }),
|
|
expect.objectContaining({ seen: true }),
|
|
],
|
|
},
|
|
})
|
|
})
|
|
})
|
|
})
|
|
})
|