53c8644f创建于 2025年4月7日历史提交
import { Test, TestingModule } from '@nestjs/testing';
import { getRepositoryToken } from '@nestjs/typeorm';
import { HttpException } from '@nestjs/common';
import { I18LangService } from '../lang.service';
import { I18, Lang } from '@app/models';
import { I18nContext, I18nService } from 'nestjs-i18n';

describe('I18LangService', () => {
  let service: I18LangService;
  let langRepositoryMock: any;
  let i18RepositoryMock: any;
  let i18nServiceMock: any;

  beforeEach(async () => {
    langRepositoryMock = {
      find: jest.fn(),
      findOneBy: jest.fn(),
      create: jest.fn(),
      save: jest.fn(),
      remove: jest.fn(),
    };

    i18RepositoryMock = {
      findOneBy: jest.fn(),
    };

    i18nServiceMock = {
      t: jest.fn(),
    };

    const module: TestingModule = await Test.createTestingModule({
      providers: [
        I18LangService,
        { provide: getRepositoryToken(Lang), useValue: langRepositoryMock },
        { provide: getRepositoryToken(I18), useValue: i18RepositoryMock },
        { provide: I18nService, useValue: i18nServiceMock },
      ],
    }).compile();
    jest.spyOn(I18nContext, 'current').mockReturnValue({
      lang: undefined
    } as any)
    service = module.get<I18LangService>(I18LangService);
  });

  it('should be defined', () => {
    expect(service).toBeDefined();
  });

  describe('findAll', () => {
    it('should return all languages', async () => {
      const languages = [{ id: 1, name: 'en' }];
      langRepositoryMock.find.mockResolvedValue(languages);

      const result = await service.findAll();

      expect(result).toEqual(languages);
      expect(langRepositoryMock.find).toHaveBeenCalled();
    });
  });

  describe('create', () => {
    it('should create a new language', async () => {
      const createLangDto = { name: 'en' };
      langRepositoryMock.findOneBy.mockResolvedValue(null);
      langRepositoryMock.create.mockReturnValue(createLangDto);
      langRepositoryMock.save.mockResolvedValue(createLangDto);

      const result = await service.create(createLangDto);

      expect(result).toEqual(createLangDto);
      expect(langRepositoryMock.findOneBy).toHaveBeenCalledWith({ name: 'en' });
      expect(langRepositoryMock.create).toHaveBeenCalled();
      expect(langRepositoryMock.save).toHaveBeenCalledWith(createLangDto);
    });

    it('should throw conflict exception if language already exists', async () => {
      const createLangDto = { name: 'en' };
      langRepositoryMock.findOneBy.mockResolvedValue(createLangDto);
      i18nServiceMock.t.mockReturnValue('Language already exists');

      await expect(service.create(createLangDto)).rejects.toThrow(HttpException);
      expect(langRepositoryMock.findOneBy).toHaveBeenCalledWith({ name: 'en' });
      expect(i18nServiceMock.t).toHaveBeenCalledWith('exception.lang.exists', {
        lang: undefined,
        args: { name: 'en' },
      });
    });
  });

  describe('findOne', () => {
    it('should return a language by id', async () => {
      const language = { id: 1, name: 'en' };
      langRepositoryMock.findOneBy.mockResolvedValue(language);

      const result = await service.findOne(1);

      expect(result).toEqual(language);
      expect(langRepositoryMock.findOneBy).toHaveBeenCalledWith({ id: 1 });
    });
  });

  describe('update', () => {
    it('should update a language', async () => {
      const language = { id: 1, name: 'en' };
      const updateData = { name: 'fr' };
      langRepositoryMock.findOneBy.mockResolvedValue(language);
      langRepositoryMock.save.mockResolvedValue({ ...language, ...updateData });

      const result = await service.update(1, updateData);

      expect(result).toEqual({ ...language, ...updateData });
      expect(langRepositoryMock.findOneBy).toHaveBeenCalledWith({ id: 1 });
      expect(langRepositoryMock.save).toHaveBeenCalledWith({
        ...language,
        ...updateData,
      });
    });

    it('should throw not found exception if language does not exist', async () => {
      langRepositoryMock.findOneBy.mockResolvedValue(null);
      i18nServiceMock.t.mockReturnValue('Language not found');

      await expect(service.update(1, { name: 'fr' })).rejects.toThrow(HttpException);
      expect(langRepositoryMock.findOneBy).toHaveBeenCalledWith({ id: 1 });
      expect(i18nServiceMock.t).toHaveBeenCalledWith('exception.lang.notExistsCommon', {
        lang: undefined,
      });
    });
  });

  describe('remove', () => {
    it('should remove a language', async () => {
      const language = { id: 1, name: 'en' };
      langRepositoryMock.findOneBy.mockResolvedValue(language);
      i18RepositoryMock.findOneBy.mockResolvedValue(null);
      langRepositoryMock.remove.mockResolvedValue(language);

      const result = await service.remove(1);

      expect(result).toEqual(language);
      expect(langRepositoryMock.findOneBy).toHaveBeenCalledWith({ id: 1 });
      expect(i18RepositoryMock.findOneBy).toHaveBeenCalledWith({ lang: language });
      expect(langRepositoryMock.remove).toHaveBeenCalledWith(language);
    });

    it('should throw not found exception if language does not exist', async () => {
      langRepositoryMock.findOneBy.mockResolvedValue(null);
      i18nServiceMock.t.mockReturnValue('Language not found');

      await expect(service.remove(1)).rejects.toThrow(HttpException);
      expect(langRepositoryMock.findOneBy).toHaveBeenCalledWith({ id: 1 });
      expect(i18nServiceMock.t).toHaveBeenCalledWith('exception.lang.notExistsCommon', {
        lang: undefined,
      });
    });

    it('should throw conflict exception if language is in use', async () => {
      const language = { id: 1, name: 'en' };
      langRepositoryMock.findOneBy.mockResolvedValue(language);
      i18RepositoryMock.findOneBy.mockResolvedValue({ lang: language });
      i18nServiceMock.t.mockReturnValue('Language is in use');

      await expect(service.remove(1)).rejects.toThrow(HttpException);
      expect(langRepositoryMock.findOneBy).toHaveBeenCalledWith({ id: 1 });
      expect(i18RepositoryMock.findOneBy).toHaveBeenCalledWith({ lang: language });
      expect(i18nServiceMock.t).toHaveBeenCalledWith('exception.lang.DELETE_LANG_CONFLICT', {
        lang: undefined,
        args: { name: 'en' },
      });
    });
  });
});