Refactor #7
This commit is contained in:
parent
f0a8adbd77
commit
661d5f4840
6 changed files with 114 additions and 4 deletions
|
|
@ -7,7 +7,10 @@
|
||||||
"build": "vue-cli-service build",
|
"build": "vue-cli-service build",
|
||||||
"lint": "vue-cli-service lint",
|
"lint": "vue-cli-service lint",
|
||||||
"format": "prettier --write .",
|
"format": "prettier --write .",
|
||||||
"prepare": "husky install"
|
"prepare": "husky install",
|
||||||
|
"test": "vitest run",
|
||||||
|
"test:watch": "vitest",
|
||||||
|
"test:coverage": "vitest run --coverage"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"core-js": "^3.8.3",
|
"core-js": "^3.8.3",
|
||||||
|
|
|
||||||
|
|
@ -55,9 +55,11 @@ Outcome: Stable formatting and consistent linting across contributors.
|
||||||
|
|
||||||
### Phase 5 — Tests (Targeted)
|
### Phase 5 — Tests (Targeted)
|
||||||
|
|
||||||
- [ ] Add a unit test runner (Vitest or Jest)
|
- [x] Add a unit test runner (Vitest)
|
||||||
- [ ] Test mappers (dates/reference wiring)
|
- [x] Test mappers (dates/reference wiring)
|
||||||
- [ ] Test `units.js` conversions and totals
|
- Added tests: `tests/mealMapper.test.js`, `tests/shoppingListMapper.test.js`
|
||||||
|
- [x] Test `units.js` conversions and totals
|
||||||
|
- Added tests: `tests/units.test.js`
|
||||||
|
|
||||||
Outcome: Confidence in refactors and easier onboarding.
|
Outcome: Confidence in refactors and easier onboarding.
|
||||||
|
|
||||||
|
|
@ -80,3 +82,5 @@ Outcome: Confidence in refactors and easier onboarding.
|
||||||
- Added `composables/useMeals.js`; migrated meal pages to composable and `<script setup>`
|
- Added `composables/useMeals.js`; migrated meal pages to composable and `<script setup>`
|
||||||
- Added `composables/useShopping.js`; migrated shopping pages to composable and `<script setup>`
|
- Added `composables/useShopping.js`; migrated shopping pages to composable and `<script setup>`
|
||||||
- Added VS Code Volar recommendation (`.vscode/extensions.json`)
|
- Added VS Code Volar recommendation (`.vscode/extensions.json`)
|
||||||
|
- Set up Vitest (`vitest.config.js`), added test scripts in `package.json`
|
||||||
|
- Wrote unit tests for mappers and units: `tests/mealMapper.test.js`, `tests/shoppingListMapper.test.js`, `tests/units.test.js`
|
||||||
|
|
|
||||||
27
tests/mealMapper.test.js
Normal file
27
tests/mealMapper.test.js
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
import { describe, it, expect } from 'vitest'
|
||||||
|
import { mapMeal, mapMeals } from '@/api/mappers/mealMapper'
|
||||||
|
|
||||||
|
describe('mealMapper', () => {
|
||||||
|
it('maps individual meal date fields to Date instances', () => {
|
||||||
|
const input = {
|
||||||
|
id: 1,
|
||||||
|
suggested_date: '2025-01-01T00:00:00Z',
|
||||||
|
purchase_date: '2025-01-02T00:00:00Z',
|
||||||
|
consumed_date: '2025-01-03T00:00:00Z',
|
||||||
|
}
|
||||||
|
const result = mapMeal({ ...input })
|
||||||
|
expect(result.suggested_date).toBeInstanceOf(Date)
|
||||||
|
expect(result.purchase_date).toBeInstanceOf(Date)
|
||||||
|
expect(result.consumed_date).toBeInstanceOf(Date)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('maps lists of meals', () => {
|
||||||
|
const input = [
|
||||||
|
{ id: 1, suggested_date: '2025-01-01T00:00:00Z' },
|
||||||
|
{ id: 2, suggested_date: '2025-01-02T00:00:00Z' },
|
||||||
|
]
|
||||||
|
const result = mapMeals(input)
|
||||||
|
expect(result).toHaveLength(2)
|
||||||
|
expect(result[0].suggested_date).toBeInstanceOf(Date)
|
||||||
|
})
|
||||||
|
})
|
||||||
33
tests/shoppingListMapper.test.js
Normal file
33
tests/shoppingListMapper.test.js
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
import { describe, it, expect } from 'vitest'
|
||||||
|
import { mapCurrentShoppingList, mapPurchasedShoppingList } from '@/api/mappers/shoppingListMapper'
|
||||||
|
|
||||||
|
describe('shoppingListMapper', () => {
|
||||||
|
it('maps current shopping list and wires references', () => {
|
||||||
|
const dto = {
|
||||||
|
ingredients_lookup: { 10: { id: 10, name: 'Eggs' } },
|
||||||
|
meals_lookup: { 1: { id: 1, suggested_date: '2025-01-01T00:00:00Z', recipes: [], extra_ingredients: [], chefs: [], consumers: [], cleanup: [] } },
|
||||||
|
recipes_lookup: { 5: { id: 5, name: 'Omelette' } },
|
||||||
|
shopping_list_lookup: { 7: { id: 7, created_date: '2025-01-01T00:00:00Z' } },
|
||||||
|
outstanding_items: [{ ingredient_id: 10, meal_id: 1, recipe_id: 5, list_id: 7, created_date: '2025-01-01T00:00:00Z' }],
|
||||||
|
requested_meals: [],
|
||||||
|
purchased_items: [],
|
||||||
|
}
|
||||||
|
const mapped = mapCurrentShoppingList(dto)
|
||||||
|
const item = mapped.outstanding_items[0]
|
||||||
|
expect(item.ingredient.name).toBe('Eggs')
|
||||||
|
expect(item.meal.suggested_date).toBeInstanceOf(Date)
|
||||||
|
expect(mapped.shopping_list_lookup['7'].created_date).toBeInstanceOf(Date)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('maps purchased shopping list with list dates and item refs', () => {
|
||||||
|
const dto = {
|
||||||
|
ingredients_lookup: { 10: { id: 10, name: 'Eggs' } },
|
||||||
|
meals_lookup: { 1: { id: 1, suggested_date: '2025-01-01T00:00:00Z', recipes: [], extra_ingredients: [], chefs: [], consumers: [], cleanup: [] } },
|
||||||
|
recipes_lookup: { 5: { id: 5, name: 'Omelette' } },
|
||||||
|
list: { id: 9, created_date: '2025-02-02T00:00:00Z', items: [{ ingredient_id: 10, meal_id: 1, recipe_id: 5, list_id: 9 }] },
|
||||||
|
}
|
||||||
|
const mapped = mapPurchasedShoppingList(dto)
|
||||||
|
expect(mapped.list.created_date).toBeInstanceOf(Date)
|
||||||
|
expect(mapped.list.items[0].recipe.name).toBe('Omelette')
|
||||||
|
})
|
||||||
|
})
|
||||||
27
tests/units.test.js
Normal file
27
tests/units.test.js
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
import { describe, it, expect } from 'vitest'
|
||||||
|
import { getConversionFactor, calculateTotals } from '@/units'
|
||||||
|
|
||||||
|
describe('units', () => {
|
||||||
|
it('returns conversion factors for aliases and base units', () => {
|
||||||
|
expect(getConversionFactor('kg')).toEqual({ unit: 'kg', factor: 1 })
|
||||||
|
expect(getConversionFactor('g')).toEqual({ unit: 'kg', factor: 1000 })
|
||||||
|
expect(getConversionFactor('kgs')).toEqual({ unit: 'kg', factor: 1 })
|
||||||
|
expect(getConversionFactor('litre')).toEqual({ unit: 'litres', factor: 1 })
|
||||||
|
expect(getConversionFactor('ml')).toEqual({ unit: 'litres', factor: 1000 })
|
||||||
|
})
|
||||||
|
|
||||||
|
it('calculates totals grouped by base units', () => {
|
||||||
|
const totals = calculateTotals([
|
||||||
|
{ quantity: 500, unit: 'g' },
|
||||||
|
{ quantity: 0.5, unit: 'kg' },
|
||||||
|
{ quantity: 250, unit: 'ml' },
|
||||||
|
{ quantity: 0.75, unit: 'litre' },
|
||||||
|
])
|
||||||
|
// Expect kg total = 0.5 (from g) + 0.5 (from kg) = 1
|
||||||
|
const kgTotal = totals.find((t) => t.unit === 'kg')
|
||||||
|
expect(kgTotal.quantity).toBeCloseTo(1)
|
||||||
|
// Expect litres total = 0.25 (from ml) + 0.75 (from litre) = 1
|
||||||
|
const lTotal = totals.find((t) => t.unit === 'litres')
|
||||||
|
expect(lTotal.quantity).toBeCloseTo(1)
|
||||||
|
})
|
||||||
|
})
|
||||||
16
vitest.config.js
Normal file
16
vitest.config.js
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
import { defineConfig } from 'vitest/config'
|
||||||
|
import { fileURLToPath } from 'node:url'
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
resolve: {
|
||||||
|
alias: {
|
||||||
|
'@': fileURLToPath(new URL('./src', import.meta.url)),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
test: {
|
||||||
|
environment: 'node',
|
||||||
|
include: ['tests/**/*.{test,spec}.js'],
|
||||||
|
globals: true,
|
||||||
|
reporters: 'default',
|
||||||
|
},
|
||||||
|
})
|
||||||
Loading…
Reference in a new issue