Skip to content

src/services/products-services.unit.test.ts โ€‹

From Week 5 in-class: testing ยท original: si-679-f-26-week05-nyt-jessicadonoho/src/services/products-services.unit.test.ts ยท all files in this project

ts
import { beforeEach, describe, expect, it, vi } from 'vitest';
import * as productsService from './products-service.js';
import * as productsRepository from '../db/products-repository.js';
import { ValidationError } from '../errors.js';
import type { Product, ProductFields } from '../models/product.js';

beforeEach(() => {
  vi.restoreAllMocks();
});

const makeProduct = (fields: ProductFields): Product => {
    return {
      id: fields.id ?? 'aaaaaaaaaaaaaaaaaaaaaaaa',
      modelName: fields.modelName ?? 'Test Product',
      modelNumber: fields.modelNumber ?? 'TP-1',
      manufacturer: fields.manufacturer ?? 'Test',
      color: fields.color ?? 'Black',
      price: fields.price ?? 10,
      quantity: fields.quantity ?? 10
    };
  };

  it('returns only the products below the threshold', async () => {
    vi.spyOn(productsRepository, 'findAllProducts').mockResolvedValue([
      makeProduct({ modelName: 'Plenty', quantity: 100 }),
      makeProduct({ modelName: 'Few', quantity: 2 }),
      makeProduct({ modelName: 'None', quantity: 0 })
    ]);
  
    const low = await productsService.getLowStockProducts(5);
  
    const names = low.map((product) => product.modelName);
  
    expect(names).toEqual(['Few', 'None']);
  });

  it('does not count a product sitting on the threshold', async () => {
    vi.spyOn(productsRepository, 'findAllProducts').mockResolvedValue([
      makeProduct({ modelName: 'Exactly five', quantity: 5 })
    ]);
  
    const low = await productsService.getLowStockProducts(5);
  
    expect(low).toHaveLength(0);
  });

  it('asks the repository to change only what it was given', async () => {
    vi.spyOn(productsRepository, 'findProduct').mockResolvedValue(
      makeProduct({ price: 10 })
    );
    const update = vi
      .spyOn(productsRepository, 'updateProduct')
      .mockResolvedValue(makeProduct({ price: 12.5 }));
  
    await productsService.updateProduct('abc', { price: 12.5 });
  
    expect(update).toHaveBeenCalledWith('abc', { price: 12.5 });
  });

  it('writes nothing when quantity would go negative', async () => {
    vi.spyOn(productsRepository, 'findProduct').mockResolvedValue(
      makeProduct({ quantity: 10 })
    );
    const update = vi.spyOn(productsRepository, 'updateProduct');
  
    await expect(
      productsService.updateProduct('abc', { quantity: -1 })
    ).rejects.toThrow(ValidationError);
  
    expect(update).not.toHaveBeenCalled();
  });