first commit
This commit is contained in:
@@ -0,0 +1,151 @@
|
||||
export class FakeRecipeRepository {
|
||||
constructor() {
|
||||
this.recipes = new Map();
|
||||
}
|
||||
|
||||
async listByOwner(ownerGoogleSub) {
|
||||
return [...this.recipes.values()].filter((recipe) => recipe.ownerGoogleSub === ownerGoogleSub);
|
||||
}
|
||||
|
||||
async findById(ownerGoogleSub, recipeId) {
|
||||
const recipe = this.recipes.get(recipeId);
|
||||
return recipe?.ownerGoogleSub === ownerGoogleSub ? recipe : null;
|
||||
}
|
||||
|
||||
async findBySource(ownerGoogleSub, platform, sourceId) {
|
||||
return [...this.recipes.values()].find((recipe) => (
|
||||
recipe.ownerGoogleSub === ownerGoogleSub
|
||||
&& recipe.source.platform === platform
|
||||
&& recipe.source.sourceId === sourceId
|
||||
)) ?? null;
|
||||
}
|
||||
|
||||
async create(document) {
|
||||
if (await this.findBySource(
|
||||
document.ownerGoogleSub,
|
||||
document.source.platform,
|
||||
document.source.sourceId,
|
||||
)) {
|
||||
const error = new Error('duplicate');
|
||||
error.code = 11000;
|
||||
throw error;
|
||||
}
|
||||
this.recipes.set(document._id, document);
|
||||
return document;
|
||||
}
|
||||
|
||||
async update(ownerGoogleSub, recipeId, changes) {
|
||||
const recipe = await this.findById(ownerGoogleSub, recipeId);
|
||||
if (!recipe) return null;
|
||||
const updated = { ...recipe, ...changes, updatedAt: new Date() };
|
||||
this.recipes.set(recipeId, updated);
|
||||
return updated;
|
||||
}
|
||||
|
||||
async delete(ownerGoogleSub, recipeId) {
|
||||
const recipe = await this.findById(ownerGoogleSub, recipeId);
|
||||
if (!recipe) return null;
|
||||
this.recipes.delete(recipeId);
|
||||
return recipe;
|
||||
}
|
||||
}
|
||||
|
||||
export class FakeAllowedEmailRepository {
|
||||
constructor(accounts = [
|
||||
{ email: 'google-user-1@example.com', canManageAccess: true },
|
||||
{ email: 'google-user-2@example.com', canManageAccess: false },
|
||||
]) {
|
||||
this.accounts = new Map(accounts.map((account) => [account.email, { ...account }]));
|
||||
}
|
||||
|
||||
async findByEmail(email) {
|
||||
return this.accounts.get(email?.trim().toLowerCase()) ?? null;
|
||||
}
|
||||
|
||||
async list() {
|
||||
return [...this.accounts.values()]
|
||||
.map(({ email }) => ({ email }))
|
||||
.sort((a, b) => a.email.localeCompare(b.email));
|
||||
}
|
||||
|
||||
async add(email, addedBy) {
|
||||
const normalizedEmail = email.trim().toLowerCase();
|
||||
const account = this.accounts.get(normalizedEmail) ?? {
|
||||
email: normalizedEmail,
|
||||
canManageAccess: false,
|
||||
addedBy,
|
||||
};
|
||||
this.accounts.set(normalizedEmail, account);
|
||||
return account;
|
||||
}
|
||||
|
||||
async remove(email) {
|
||||
return this.accounts.delete(email.trim().toLowerCase());
|
||||
}
|
||||
}
|
||||
|
||||
export const fakeUserRepository = {
|
||||
async upsertGoogleUser(profile) {
|
||||
return profile;
|
||||
},
|
||||
};
|
||||
|
||||
export function createTestConfig(overrides = {}) {
|
||||
return {
|
||||
nodeEnv: 'test',
|
||||
host: '127.0.0.1',
|
||||
port: 3000,
|
||||
logLevel: 'silent',
|
||||
publicBaseUrl: 'http://localhost:3000',
|
||||
mongoUri: 'mongodb://localhost:27017/our_recipe_atlas_test',
|
||||
mongoFallbackUri: undefined,
|
||||
imageRoot: new URL('../../data/images', import.meta.url).pathname,
|
||||
google: {
|
||||
clientId: undefined,
|
||||
clientSecret: undefined,
|
||||
callbackUrl: 'http://localhost:3000/auth/google/callback',
|
||||
allowedEmails: new Set(['allowed@example.com']),
|
||||
},
|
||||
authJwtSecret: 'test-secret-that-is-long-enough-for-tests',
|
||||
authSessionTtlHours: 24,
|
||||
minimax: {
|
||||
apiKey: undefined,
|
||||
baseUrl: 'https://api.minimax.io/v1',
|
||||
model: 'MiniMax-M2.7',
|
||||
},
|
||||
instagramSessionCookie: undefined,
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
export const recipeDraft = {
|
||||
title: '김치찌개',
|
||||
summary: '간단한 김치찌개',
|
||||
servings: '2인분',
|
||||
ingredientGroups: [
|
||||
{
|
||||
name: '재료',
|
||||
items: [
|
||||
{ name: '김치', amount: '200g' },
|
||||
{ name: '물', amount: '500ml' },
|
||||
],
|
||||
},
|
||||
],
|
||||
steps: [
|
||||
{ order: 1, text: '김치를 볶는다.', timestampSec: null },
|
||||
{ order: 2, text: '물을 넣고 끓인다.', timestampSec: null },
|
||||
],
|
||||
tips: ['신김치를 사용한다.'],
|
||||
tags: ['한식'],
|
||||
};
|
||||
|
||||
export const source = {
|
||||
platform: 'instagram',
|
||||
sourceUrl: 'https://www.instagram.com/reel/Db137BuzUJe/',
|
||||
sourceId: 'Db137BuzUJe',
|
||||
title: '김치찌개',
|
||||
author: 'recipe_author',
|
||||
thumbnailUrl: 'https://images.example.com/cover.jpg',
|
||||
rawText: '김치 200g과 물 500ml를 넣고 끓입니다.',
|
||||
metadata: {},
|
||||
};
|
||||
Reference in New Issue
Block a user