import ava, { TestInterface } from 'ava'; import { Mongoose, Types } from 'mongoose'; import { Factory } from '../../../database/factory'; import * as testUtils from '../../../test/utils'; import { User, UserProps } from '../../user'; import { Recipe } from '..'; import { createContext } from '../../../test/utils/create-mock-context'; import { gqlCall } from '../../../test/utils/gqlCall'; import { RecipeProps } from '../recipe-model'; import { defineUserAbility } from '../../../server/authorization/user-authorization'; import { UserInputError, ForbiddenError, AuthenticationError, } from 'apollo-server-micro'; // // Setup // const test = ava as TestInterface<{ db: Mongoose }>; test.before(async t => { await testUtils.setupDB(t); }); test.afterEach.always(async t => { await testUtils.cleanupDB(t); }); test.after.always(async t => { await testUtils.tearDownDB(t); }); // // Constants // const deleteRecipeMutation = ` mutation Delete($input: DeleteRecipeInput) { deleteRecipe(input: $input) { id title } } `; // // Tests // test.serial('Should delete recipe from database', async t => { const user = await Factory.create('user'); const recipe = await Factory.create('recipe', { ownerId: user.id, }); const context = createContext({ state: { user, abilities: defineUserAbility(user) }, }); const response = await gqlCall({ source: deleteRecipeMutation, contextValue: context, variableValues: { input: { id: recipe.id }, }, }); const retrievedRecipe = await Recipe.findById(recipe.id); t.is(retrievedRecipe, null); }); test.serial('Should return deleted recipe', async t => { const user = await Factory.create('user'); const recipe = await Factory.create('recipe', { ownerId: user.id, }); const context = createContext({ state: { user, abilities: defineUserAbility(user) }, }); const response = await gqlCall({ source: deleteRecipeMutation, contextValue: context, variableValues: { input: { id: recipe.id }, }, }); t.is(response.data.deleteRecipe.id, recipe.id); }); test.serial('Should thow error when no user is not logged in', async t => { const context = createContext({ state: { user: null } }); const response = await gqlCall({ source: deleteRecipeMutation, contextValue: context, variableValues: { input: { id: '' }, }, }); t.truthy(response.errors.length > 0); t.true(response.errors[0].originalError instanceof AuthenticationError); }); test.serial('Should thow error when user does not own the Recipe', async t => { const user = await Factory.create('user'); const recipe = await Factory.create('recipe'); const context = createContext({ state: { user, abilities: defineUserAbility(user) }, }); const response = await gqlCall({ source: deleteRecipeMutation, contextValue: context, variableValues: { input: { id: recipe.id }, }, }); t.truthy(response.errors.length > 0); t.true(response.errors[0].originalError instanceof ForbiddenError); }); test.serial('Should thow error when Recipe does not exist', async t => { const user = await Factory.create('user'); const context = createContext({ state: { user, abilities: defineUserAbility(user) }, }); const response = await gqlCall({ source: deleteRecipeMutation, contextValue: context, variableValues: { input: { id: Types.ObjectId().toHexString() }, }, }); t.truthy(response.errors.length > 0); t.true(response.errors[0].originalError instanceof ForbiddenError); }); test.serial('Should thow error when Recipe id is malformed', async t => { const user = await Factory.create('user'); const context = createContext({ state: { user, abilities: defineUserAbility(user) }, }); const response = await gqlCall({ source: deleteRecipeMutation, contextValue: context, variableValues: { input: { id: 'malformed' }, }, }); t.truthy(response.errors.length > 0); t.true(response.errors[0].originalError instanceof UserInputError); });