프로젝트 & 테스트코드(cypress & jest) 절대 경로 설정하기

Lemon·2023년 5월 17일
1

Yarn Berry 프로젝트

목록 보기
3/3
post-thumbnail

개발 환경
Yarn Berry(yarn2)
React
TypeScript
Jest
Cypress

폴더 구조

📦project
	...
 ┣ 📂.yarn
 ┣ 📂cypress
 ┃ ┣ 📂e2e
 ┃ ┃ ┗ 📂api
 ┃ ┃ ┃ ┗ 📜test.cy.js
 ┃ ┣ 📂fixtures
 ┃ ┃ ┗ 📜example.json
 ┃ ┗ 📂support
 ┃ ┃ ┣ 📜commands.js
 ┃ ┃ ┗ 📜e2e.js
 ┣ 📂public
   ...
 ┣ 📂src
 ┃ ┣ 📂api
 ┃ ┃ ┗ 📜sample.ts
 ┃ ┣ 📂utils
 ┃ ┃ ┗ 📜sample.ts
 	...
 ┣ 📂test
 ┃ ┗ 📜sample.test.ts
 ┣ 📜.eslintrc.json
 ┣ 📜.gitignore
 ┣ 📜.pnp.cjs
 ┣ 📜.pnp.loader.mjs
 ┣ 📜.prettierrc.json
 ┣ 📜.yarnrc.yml
 ┣ 📜cypress.config.ts
 ┣ 📜jest.config.ts
 ┣ 📜package.json
 ┣ 📜README.md
 ┣ 📜tsconfig.json
 ┗ 📜yarn.lock

1. 프로젝트 절대 경로 설정하기


"baseUrl": "src" 추가

ts.config.json에서 "baseUrl": "src" 추가한다.

{
    "compilerOptions": {
        "target": "es5",
        "lib": ["dom", "dom.iterable", "esnext"],
        "types": ["cypress"],
        "allowJs": true,
        "skipLibCheck": true,
        "esModuleInterop": true,
        "allowSyntheticDefaultImports": true,
        "strict": true,
        "forceConsistentCasingInFileNames": true,
        "noFallthroughCasesInSwitch": true,
        "module": "esnext",
        "moduleResolution": "node",
        "resolveJsonModule": true,
        "isolatedModules": true,
        "noEmit": true,
        "jsx": "react-jsx",
        "baseUrl": "src"
    },
    "include": ["src"]
}

baseUrl은 상대 경로를 계산할 기본 디렉토리를 지정한다. 여기서는 "src"를 기본 디렉토리로 설정한다.


2. 테스트 코드 절대 경로 설정하기


2-1. jest 절대 경로 작성

2-1-1. jest.config.js 에 아래 내용 추가

// Jest 특정경로 테스트 진행 X
testPathIgnorePatterns: ['<rootDir>/cypress/'],
// Jest 절대경로 사용
moduleNameMapper: {
	'^@/(.*)$': '<rootDir>/$1',
	'^utils/(.*)': '<rootDir>/src/utils/$1',
},

실행 에러 jest-config tried to access ts-node

Error: Jest: Failed to parse the TypeScript config file C:\Users\smt\Desktop\Remon\dpms_fe\jest.config.ts
Error: jest-config tried to access ts-node (a peer dependency) but it isn't provided by its ancestors; this makes the require call ambiguous and unsound.
Required package: ts-node (via "ts-node\package.json")
Required by: jest-config@virtual:6a53c2378e7cba6f9934905320933b15fb461ebc13bfaf566ba916aee80e6cee2098933b51ddd0bc9e6d3f79ebcbb07767b5e1fa4abadd019ff19d8b2cf1bfe9#npm:29.5.0 (via C:\Users\smt\Desktop\Remon\dpms_fe\.yarn\**virtual**\jest-config-virtual-9dc828f591\0\cache\jest-config-npm-29.5.0-15ac67fe8b-c37c4dab96.zip\node_modules\jest-config\build\readConfigFileAndSetRootDir.js)

이 오류는 jest-config 모듈이 ts-node 모듈에 대한 peer dependency를 찾을 수 없기 때문에 발생하는 것이다. 이 문제를 해결하기 위해서는 ts-node 모듈을 설치한다.

yarn add -D ts-node

실행 에러 Unable to compile TypeScript

Error: Jest: Failed to parse the TypeScript config file C:\Users\smt\Desktop\Remon\dpms_fe\jest.config.ts
TSError: ⨯ Unable to compile TypeScript:
jest.config.ts:5:1 - error TS2591: Cannot find name 'module'. Do you need to install type definitions for node? Try npm i --save-dev @types/node and then add 'node' to the types field in your tsconfig.
5 module.exports = {

이 오류는 jest.config.ts에서 TypeScript에서 import/export 구문을 인식하지 못하기 때문에 발생할 수 있다. 그래서 module.exports 대신에 export default를 사용하여 Jest 구성을 내보내야한다.

2-1-2. @jest/types 설치

yarn add -D @jest/types

export default 를 사용하기 위해 @jest/types 설치한다.

2-1-3. ts.config.js 내용 변경

import type { Config } from '@jest/types';

const config: Config.InitialOptions = {
  preset: 'ts-jest',
  testEnvironment: 'node',
  verbose: true,
  collectCoverage: true,

  // Jest 특정경로 테스트 진행 X
  testPathIgnorePatterns: ['<rootDir>/cypress/'],
  // Jest 절대경로 사용
  moduleNameMapper: {
    '^@/(.*)$': '<rootDir>/$1',
    '^utils/(.*)': '<rootDir>/src/utils/$1',
  },
};

export default config;

2-1-4. 절대경로 적용 테스트

간단한 테스트를 만들어서 절대경로가 제대로 적용되었는지 확인해보자

  1. src/utils 폴더에서 test를 위한 간단한 sample 함수가 있는 sample.ts를 만든다.
export function sam(props: { a: number; b: number }) {
    const { a, b } = props;
    return a + b;
}
  1. test폴더에 sample.test.ts 테스트 파일을 만들고 sample.ts 파일을 import 해서 절대경로가 적용되는지 확인한다.
import { sam } from 'utils/sample';

it('test', () => {
    expect(sam({ a: 1, b: 2 }));
});

it('ENV Test', async () => {
    const testApi = process.env.REACT_APP_TEST_API;
    if (testApi) {
        expect(testApi).toBe('https://jsonplaceholder.typicode.com/posts/1');
    }
});

만약 위와같이 “모듈 또는 해당 형식 선언을 찾을 수 없습니다. ts(2307)” 오류가 나온다면 tsconfig.json 파일에 include에 어떤 파일들을 baseUrl 속성을 포함시킬지 작성해줘야한다.

{
    "compilerOptions": {
        "target": "ES2022",
        "lib": ["dom", "dom.iterable", "esnext"],
        "types": ["cypress"],
        "allowJs": true,
        "skipLibCheck": true,
        "esModuleInterop": true,
        "allowSyntheticDefaultImports": true,
        "strict": true,
        "forceConsistentCasingInFileNames": true,
        "noFallthroughCasesInSwitch": true,
        "module": "esnext",
        "moduleResolution": "node",
        "resolveJsonModule": true,
        "isolatedModules": true,
        "noEmit": true,
        "jsx": "react-jsx",
        "baseUrl": "src"
    },
    "include": ["src", "test/*.test.ts"]
}

jest test를 작성하는 폴더의 경로를 include에 작성한다.

  1. yarn jest로 적용을 확인한다.

2-2. cypress 절대 경로 설정

2-2-1. @cypress/webpack-preprocessor 설치

yarn add -D @cypress/webpack-preprocessor

웹팩 설정을 위한 @cypress/webpack-preprocessor 설치한다.

2-2-2. cypress.config.ts 에 절대경로 내용 추가

const webpack = require('@cypress/webpack-preprocessor');
const path = require('path');

module.exports = {
    e2e: {
        baseUrl: 'https://localhost:3000',
        setupNodeEvents(on, config) {
            const options = webpack({
                webpackOptions: {
                    resolve: {
                        extensions: ['.ts', '.tsx', '.mjs', '.cjs'],
                        alias: {
                            cypress: path.resolve(
                                __dirname,
                                'cypress',
                                'e2e',
                                'api',
                            ),
                            api: path.resolve(__dirname, 'src', 'api'),
                        },
                    },
                },
            });
            on('file:preprocessor', options);
            return config;
        }
    }
};
  • const webpack = require('@cypress/webpack-preprocessor');
    • @cypress/webpack-preprocessor 패키지를 가져와서 webpack을 사용할 수 있도록 한다.
  • const path = require('path');
    • Node.js의 path 모듈을 가져온다.
  • module.exports를 통해 Cypress의 구성을 내보낸다.
    • 구성은 e2e 객체로 정의되어 있다.
      • e2e 객체 속성
        • baseUrl: 테스트 시나리오에서 사용할 기본 URL을 설정한다.
        • setupNodeEvents: Cypress 플러그인 API의 setupNodeEvents 메서드를 사용하여 Node 이벤트를 설정한다. 이 메서드는 onconfig 매개변수를 사용한다. setupNodeEvents 메서드 내부에서는 @cypress/webpack-preprocessor를 사용하여 Webpack 설정을 정의한다.
          • webpackOptions: Webpack 설정을 정의하는 객체이다.
            • resolve: 모듈 해석에 대한 설정을 정의하는 객체이다.
              • extensions: 모듈 해석에 사용될 확장자를 정의하는 배열이다.
                • .ts, .tsx, .mjs, .cjs 확장자를 사용할 수 있도록 지정한다.
              • alias: 모듈 별칭을 정의하는 객체이다.
                • cypress 별칭
                  • cypress: path.resolve( __dirname,'cypress','e2e','Api',) 위의 경로는 cypress/e2e/Api
                • api 별칭은 다른 경로로 해석되도록 설정되어 있다.
          • on('file:preprocessor', options); : 파일 프리프로세서 이벤트를 등록한다. 이를 통해 Webpack 프리프로세서가 파일 처리를 수행할 수 있도록 한다. 이 구성을 반환하여 전체 Cypress 구성이 완료된다.

2-2-3. 절대경로 적용 테스트

간단한 테스트를 만들어서 절대경로가 제대로 적용되었는지 확인해보자

  1. src/api폴더에서 test를 위해 오픈 api url이 들어있는 sample.ts를 만든다.
export const testUrl = 'https://jsonplaceholder.typicode.com/posts/1';

  1. cypress/e2e/api폴더에 test.cy.js 테스트 파일을 만들고 sample.ts 파일에 있는 testUrl을 import 해서 절대경로가 적용되는지 확인한다.
import { testUrl } from 'api/sample';

it('API Test', () => {
    cy.request(testUrl).then(response => {
        expect(response.status).to.eq(200);
        expect(response.body.title).to.eq(
            'sunt aut facere repellat provident occaecati excepturi optio reprehenderit',
        );
    });
});

it('ENV Test', () => {
    cy.request(Cypress.env('TEST_API')).then(response => {
        expect(response.status).to.eq(200);
        expect(response.body.title).to.eq(
            'sunt aut facere repellat provident occaecati excepturi optio reprehenderit',
        );
    });
});

  1. yarn cypress로 실행해본다.

실행 에러 Can't resolve './commands'

Error: Webpack Compilation Error
Module not found: Error: Can't resolve './commands' in

위와 같이 실행에러가 뜬다면 cypress.config.tssupportFile 속성 추가한다.

const webpack = require('@cypress/webpack-preprocessor');
const path = require('path');

module.exports = {
    e2e: {
        baseUrl: 'https://localhost:3000',
        setupNodeEvents(on, config) {
            const options = webpack({
                webpackOptions: {
                    resolve: {
                        extensions: ['.ts', '.tsx', '.mjs', '.cjs'],
                        alias: {
                            cypress: path.resolve(
                                __dirname,
                                'cypress',
                                'e2e',
                                'Api',
                            ),
                            api: path.resolve(__dirname, 'src', 'api'),
                        },
                    },
                },
            });
            on('file:preprocessor', options);
            return config;
        },
        supportFile: 'cypress/support/commands.js',
    }
};

이렇게 하면 commands.js 파일이 Cypress에서 로드된다.

supportFile에 지정한 파일은 before 또는 beforeEach 훅에서 사용할 수 있는 유틸리티 함수를 정의하거나, 브라우저 환경을 설정하는 코드를 작성하는 등의 용도로 사용된다.

이 속성을 사용하면 Cypress 실행 중에 로드할 수 있는 추가적인 스크립트 파일의 경로를 지정할 수 있다. 이 파일들은 모든 테스트 파일보다 먼저 로드된다.


  1. yarn cypress로 적용을 확인한다.

3. yarn start.eslintrc.json files 오류

[eslint] ESLint configuration in .eslintrc.json is invalid:
- Unexpected top-level property "files".

yarn start를 했는데 위와 같은 오류가 나온다면 tsconfig.json파일에서 "include": ["src", "cypress/**/*.ts"] 를 추가해주면 오류가 해결된다.

{
    "compilerOptions": {
        "target": "ES2022",
        "lib": ["dom", "dom.iterable", "esnext"],
        "types": ["cypress"],
        "allowJs": true,
        "skipLibCheck": true,
        "esModuleInterop": true,
        "allowSyntheticDefaultImports": true,
        "strict": true,
        "forceConsistentCasingInFileNames": true,
        "noFallthroughCasesInSwitch": true,
        "module": "esnext",
        "moduleResolution": "node",
        "resolveJsonModule": true,
        "isolatedModules": true,
        "noEmit": true,
        "jsx": "react-jsx",
        "baseUrl": "src"
    },
    **"include": ["src", "cypress/**/*.ts", "test/*.test.ts"]**
}

위와 같은 오류가 나오는 이유는 .eslintrc.json 파일에서 "files": ["cypress/**/*.ts"] 속성을 사용했기 때문이다.

"files" 속성은 ESLint가 린트링을 수행할 파일을 지정하는 속성인데, 현재 프로젝트에서는 cypress 폴더 아래에 있는 모든 하위 폴더에서 .ts확장자를 가진 파일을 대상으로 ESLint 린트링을 수행하도록 설정하고 있다.

그러나 해당 오류는 .eslintrc.json 파일에서 예상치 못한 files 속성이 발견되었다는 것을 알려준다.

tsconfig.json baseUrl을 설정하면 TypeScript 컴파일러는 baseUrl을 기준으로 모듈을 찾습니다. 하지만 `"files": ["cypress//*.ts"]`** 설정을 추가하면 ESLint는 해당 경로 아래의 파일만 검사하고 그 외의 경로에 있는 파일은 검사하지 않게 됩니다. 이때 검사 대상에서 제외된 파일 중 baseUrl 설정에 따라 모듈을 찾을 수 없는 파일이 있어서 해당 오류가 발생한 것으로 보인다.

따라서 해당 오류를 해결하기 위해서는, tsconfig.json 파일에서 "include"`"cypress//*.ts"`를** 추가해주면 된다.

profile
프론트엔드 개발자 가보자고~!!

0개의 댓글