import { ApolloServer } from 'apollo-server-express'; import faker from 'faker'; import gql from 'graphql-tag'; import { setupApolloServer } from '../src/config/apollo'; import { ACCESS_TOKEN_HEADER_NAME, REFRESH_TOKEN_COOKIE_NAME, } from '../src/constants'; import { User } from '../src/entities'; import { ContextType } from '../src/types'; export const execute = async ( options: Parameters[0], context?: { accessToken?: string; refreshToken?: string; }, executionOptions?: { req?: Record; res?: Record; } ): Promise> => { const { accessToken, refreshToken } = context || {}; const apollo = await setupApolloServer(); return await apollo.executeOperation(options, { req: executionOptions?.req ?? { headers: { [ACCESS_TOKEN_HEADER_NAME]: accessToken, }, cookies: { [REFRESH_TOKEN_COOKIE_NAME]: refreshToken, }, }, res: executionOptions?.res ?? { cookie: () => { // no-op }, clearCookie: () => { // no-op }, }, }); }; export const signUp = async (options?: { username?: string; password?: string; email?: string; skipVerification?: boolean; }) => { const { username, password, email, skipVerification } = { username: faker.internet.userName(), password: faker.internet.password(40), email: faker.internet.email(), ...options, }; const response = await execute({ query: gql` mutation ($input: SignUpInput!) { signUp(input: $input) { accessToken user { id } } } `, variables: { input: { email, username, password, }, }, }); // verify users in test if (!skipVerification) { const user = await User.findOne(response?.data?.signUp?.user?.id, { relations: ['passwordAuth'], }); if (user?.passwordAuth) { user.passwordAuth.isVerified = true; await user.passwordAuth.save(); } } return response; }; export const signUpAnonymously = async (options?: Record) => { const response = await execute({ query: gql` mutation ($input: SignUpAnonymouslyInput!) { signUpAnonymously(input: $input) { accessToken user { id } } } `, variables: { input: {}, }, }); return response; }; export const getUser = async (): Promise => { const response = await signUp(); return User.findOneOrFail({ id: response?.data?.signUp?.user?.id }); }; export const signIn = async (options?: { username?: string; password?: string; email?: string; }) => { const { username, password } = { username: faker.internet.userName(), password: faker.internet.password(40), ...options, }; return await execute({ query: gql` mutation ($input: SignInInput!) { signIn(input: $input) { accessToken user { id } } } `, variables: { input: { username: username, password: password, }, }, }); }; export const authExecute = async ( options: Parameters[0] ): Promise> => { const response = await signUp(); const accessToken = response.data?.signUp?.accessToken; return await execute(options, { accessToken, }); }; /** * startSession enables the user to get an authenticated execute function that * will use the same auth credentials upon multiple queries or mutations. */ export const startSession = async ( options?: Parameters[0] ): Promise<{ execute: ApolloServer['executeOperation']; user: User; context: ContextType; }> => { const response = await signUp(options); const accessToken = response.data?.signUp?.accessToken; const sessionExecute = async (...args: Parameters) => { return execute(args[0], { ...args[1], accessToken, }); }; const user = await User.findOneOrFail(response.data?.signUp?.user.id); return { execute: sessionExecute, user, // NOTE: this should be sufficient for testing as most context accessors // only require the user context: { accessToken, user, } as ContextType, }; }; /** * startSession enables the user to get an authenticated execute function that * will use the same auth credentails upon multiple queries or mutations. */ export const startSessionAnonymously = async ( options?: Parameters[0] ): Promise<{ execute: ApolloServer['executeOperation']; user: User; context: ContextType; }> => { const response = await signUpAnonymously(options); const accessToken = response.data?.signUpAnonymously?.accessToken; const sessionExecute = async (...args: Parameters) => { return execute(args[0], { ...args[1], accessToken, }); }; const user = await User.findOneOrFail( response.data?.signUpAnonymously?.user.id ); return { execute: sessionExecute, user, // NOTE: this should be sufficient for testing as most context accessors // only require the user context: { accessToken, user, } as ContextType, }; };