jest 를 이용한 e2e 테스트 중

원하는 응답이 나오지 않을때 fail 이 뜨는데 콘솔에는 단순하게  이렇게 만 뜬다.

 expected 201 "Created", got 404 "Not Found"

 

expected 201 "Created", got 401 "Unauthorized"

 

내가 알고 싶은 것들

1. 어느 부분에서 문제가 생기는지?

2. 실패했을때 받은 에러 메세지의 자세한 내용이 무엇인지?

3. 응답값이 제대로 나왓는지?

에 대한 정보를 console.log 로 찍어보려다 보는 것이 너무 어려워서 검색하다가

 

해결방법을 찾았다.

 아래 코드를 추가하여 response 가 무엇인지 알아 보는 것이다.

.expect((res) => {
  expect(res.body).toHaveProperty('setCount');
})

- {} 안에는 자신이 예상되는 값이 있는지 확인하기 위한 용도

it('save workoutLogs', () => {
      token = generateTestToken(1);
      return (
        request(app.getHttpServer())
          .post('/workout-logs/')
          .set('Authorization', `Bearer ${token}`)
          .send(mockWorkoutLogSave)
          // .expect((res) => {
          //   expect(res.body).toHaveProperty('setCount');
          // })
          .expect(201)
      );
    });

 

1. 코드를 추가

2. 하나하나 주석처리를 해가면서 어느 부분에서 문제가 생기는지 파악

 

이렇게 하면 해결가능

e2e 테스트를 하다가 발생한 에러

ERROR [TypeOrmModule] Unable to connect to the database. Retrying (1)... Error: DataSource with name "default" has already added.

 

검색을 하여 찾은 아래의 링크를 따라 해결

https://github.com/Aliheym/typeorm-transactional/issues/10

 

Error when running E2E tests with Nest.js · Issue #10 · Aliheym/typeorm-transactional

Hi there, thanks for the package! It really is super useful. My issue is that we can't run our E2E tests with it as of now. We get the console error Error: DataSource with name "default" has alread...

github.com

 

두가지 해결 방식

방식 1. getDataSourceByName('default') 추가

import { addTransactionalDataSource, getDataSourceByName } from 'typeorm-transactional';

// ...

TypeOrmModule.forRootAsync({
    dataSourceFactory: async (options) => {
      return getDataSourceByName('default') || addTransactionalDataSource(new DataSource(options));
    },
  });

 

방식 2. deleteDataSourceByName('default') 추가

import { addTransactionalDataSource, deleteDataSourceByName } from 'typeorm-transactional';

// ...

TypeOrmModule.forRootAsync({
    dataSourceFactory: async (options) => {
      deleteDataSourceByName('default');

      return addTransactionalDataSource(new DataSource(options));
    },
  });

 

각 방식에서 사용된 코드의 의미???

import { DataSource, EntityManager, Repository } from 'typeorm';
...
export type DataSourceName = string | 'default';
const dataSources = new Map<DataSourceName, DataSource>();

export const getDataSourceByName = (name: DataSourceName) => dataSources.get(name);
export const deleteDataSourceByName = (name: DataSourceName) => dataSources.delete(name);

 

 

방식 1 을 선택하여   getDataSourceByName('default') 코드를 추가하여 해결

//변경 전
 async dataSourceFactory(options) {
    if (!options) {
      throw new Error('Invalid options passed');
    }
    return addTransactionalDataSource(new DataSource(options));
  },
  
// 변경 후
 async dataSourceFactory(options) {
    if (!options) {
      throw new Error('Invalid options passed');
    }
    return getDataSourceByName('default') || addTransactionalDataSource(new DataSource(options));
  },

 

 

이렇게 하니 귀찮은 일이 발생했다.

1. 앞의 테스트에서 내가 생성한 유저를 다시 생성하려면 이미 있는 e-mail 이라는 문구가 발생

2. 앞의 테스트에서 내가 지운 유저를 또 지우려면 내가 원하는 204가 아니라 500 반환

 

beforeAll 을 이용하여서 하니 

  • 옵션< getDataSourceByName('default') >을 추가하지 않아도 해당 에러가 뜨지 않았다. Error: DataSource with name "default" has already added.
  • 테스트할때마다 내가 적은 expect 부분을 수정하지 않아도 되었다.

의문점

  • beforeEach 에서는 중복이 발생했는데 어떻게 beforeAll 에서는 중복이 발생하지 않을까

-> 데이터베이스를 확인해보니 역시나 중복이 발생. 중복을 방지하기 위해  

 

최종적으로 테이블을 드랍하고 동기화 하는 코드를 추가하여 마무리하였다.

 beforeAll(async () => {
    initializeTransactionalContext();
    const moduleFixture: TestingModule = await Test.createTestingModule({
      imports: [AppModule],
    }).compile();
    
    dataSource = moduleFixture.get<DataSource>(DataSource);
    
    // 데이터베이스 테이블 초기화 및 동기화
    await dataSource.dropDatabase();
    await dataSource.synchronize();
    
    // 토큰 발행
    token = generateTestToken();
    
    app = moduleFixture.createNestApplication();
    await app.init();
  });

 

※ 데이테베이스 테이블 초기화를 beforeEach에 사용하면 생성한 유저가 사라져서 jwt 토큰을 발행하는데 문제가 발생한다.

오류 내용

[remote rejected] main -> main (refusing to allow a Personal Access Token to create or update workflow `.github/workflows/deploy.yml` without `workflow` scope)

 

Access Token 이  workflow 를 수정하거나 업데이트할 권한이 없다.

 

해결방법

깃허브 홈페이지에서 

Settings > Developer Settings > Token  으로 이동

 

발급된 토근에서  workflow 클릭 하여 허용된 목록을 수정한다.

 

board.service.ts 에서 아래와 같이 다른 서비스를 이용하려니까 발생한 문제

@Injectable()
export class BoardService {
  constructor(
    private readonly hashtagService: HashtagService,
    private readonly categoryService: CategoryService,
    private readonly boardToCategoryService: BoardToCategoryService,
    private readonly hashtagToBoardService: HashtagToBoardService,
    @InjectRepository(Board)
    private readonly boardRepository: Repository<Board>,
  ) {}

 

 

에러문구

 ERROR [ExceptionHandler] Nest can't resolve dependencies of the BoardService (HashtagService, CategoryService, ?, HashtagToBoardService, BoardRepository). Please make sure that the argument BoardToCategoryService at index [2] is available in the BoardModule context.

Potential solutions:
- Is BoardModule a valid NestJS module?
- If BoardToCategoryService is a provider, is it part of the current BoardModule?
- If BoardToCategoryService is exported from a separate @Module, is that module imported within BoardModule?
  @Module({
    imports: [ /* the Module containing BoardToCategoryService */ ]
  })

 

 

해결방식

1. 오류내용을 확인 -> 잘 이해가 안된다.

2. 오류메세지를 구글링 -> module의 imports 부분에 추가를 해주거나 중복된것이 있는지 확인해야 한다고함.

3. 다시 오류메시지 확인

->  솔류션에 적혀있는 대로 내가 사용하려는 서비스가 BoardModule의 일부분이 아니였다.

 

오류 코드

import { BoardController } from './board.controller';
import { BoardService } from './board.service';
import { TypeOrmModule } from '@nestjs/typeorm';
import { Board } from '../../entities/Board.entity';

@Module({
  imports: [
    TypeOrmModule.forFeature([Board]),
  ],
  controllers: [BoardController],
  providers: [BoardService],
})
export class BoardModule {}

 

해결한 코드

import { BoardController } from './board.controller';
import { BoardService } from './board.service';
import { TypeOrmModule } from '@nestjs/typeorm';
import { Board } from '../../entities/Board.entity';
import { HashtagModule } from '../hashtag/hashtag.module';
import { HashtagToBoardModule } from '../hashtag_board/hashtagToBoard.module';
import { BoardToCategoryModule } from '../board_category/boardToCategory.module';
import { CategoryModule } from '../category/category.module';

@Module({
  imports: [
    TypeOrmModule.forFeature([Board]),
    CategoryModule,
    HashtagModule,
    BoardToCategoryModule,
    HashtagToBoardModule,
  ],
  controllers: [BoardController],
  providers: [BoardService],
  exports: [BoardService],
})
export class BoardModule {}

 

< 추가로 설정해야하는 부분 >

imports 한 각 module에 내가 사용할 service를 exports 해줘야한다.

예시

import { Module } from '@nestjs/common';
import { ReplyController } from './reply.controller';
import { ReplyService } from './reply.service';
import { TypeOrmModule } from '@nestjs/typeorm';
import { Reply } from '../../entities/entity.index';

@Module({
  imports: [TypeOrmModule.forFeature([Reply])],
  controllers: [ReplyController],
  providers: [ReplyService],
  exports: [ReplyService], // <--- 이 부분을 써줘야 다른 곳에서 서비스 사용가능
})
export class ReplyModule {}

 

 

마치 app.module.ts 에서 내가 만든 서비스를 사용하기 위해서 다른 모듈을 다 imports에 넣듯이

여기서도 같은 원리로 내가 원하는 서비스를 포함하는 모듈을 imports에 넣으면 되는 것이였다.

설치한 라이브러리

https://www.npmjs.com/package/typeorm-snake-naming-strategy

 

typeorm-snake-naming-strategy

Snake naming strategy for TypeORM.. Latest version: 1.0.2, last published: 4 years ago. Start using typeorm-snake-naming-strategy in your project by running `npm i typeorm-snake-naming-strategy`. There is 1 other project in the npm registry using typeorm-s

www.npmjs.com

 

상황:

TypeORM 에서 snakeCase 로 자동으로 바꿔주는 라이브러리를 설치했는데 위와 같은 에러가 뜸

 

이유:

ES 버전이 맞지 않아서 생기는 오류

 

문제

이것 때문에 setting에서 ES 버전도 바꾸어보고 했는데 

결국, 위에서 설치한 라이브러리가 너무 오래 된것이다.... 

 

최신버전으로 배포된 아래 라이브러리를 설치 하니 바로 해결된다... 라이브러리 이름이 너무 똑같다;;;;

https://www.npmjs.com/package/typeorm-naming-strategies

 

typeorm-naming-strategies

Custom naming strategies for typeorm. Latest version: 4.1.0, last published: 2 years ago. Start using typeorm-naming-strategies in your project by running `npm i typeorm-naming-strategies`. There are 98 other projects in the npm registry using typeorm-nami

www.npmjs.com

 

 

라이브러리는 항상 최신버전으로!!!

공개된지 너무 오래된 것이 있으면 한번 의심해보고 최신버전이 있는지 찾아보자

+ Recent posts