Skip to content

Commit

Permalink
Merge branch 'backghho' into be-dev
Browse files Browse the repository at this point in the history
  • Loading branch information
Arachneee authored Sep 26, 2024
2 parents 89ed425 + 30b6f5e commit 50cf06a
Show file tree
Hide file tree
Showing 372 changed files with 39,406 additions and 1 deletion.
2 changes: 2 additions & 0 deletions .github/workflows/backend-prod.yml
Original file line number Diff line number Diff line change
Expand Up @@ -91,3 +91,5 @@ jobs:

- name: Docker run
run: sudo docker run -d -p 80:8080 -e SPRING_PROFILES_ACTIVE=prod -v log-volume:/app/logs --name haengdong-backend ${{ secrets.DOCKER_USERNAME }}/${{ secrets.DOCKER_IMAGE_BE_DEV }}


91 changes: 91 additions & 0 deletions .github/workflows/frontend-pull-request.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
name: frontend-pull-request

on:
pull_request:
types: [opened, synchronize]
branches: [main, fe-dev]
paths:
- "client/**"

jobs:
test:
runs-on: ubuntu-latest

defaults:
run:
shell: bash
working-directory: ./client

steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: "20.15.1"

- name: Install dependencies
run: npm install

- name: Run lint
run: npm run lint

- name: Run test
run: npm run test

- name: Cypress test
run: npm run dev &
env:
CI: true

- name: Wait for the server to start
run: sleep 3

- name: Run Cypress tests
run: npm run cypress-run

chromatic:
name: Run Chromatic
runs-on: ubuntu-latest

defaults:
run:
shell: bash
working-directory: ./client

steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: "20.15.1"

- name: Cache dependencies
id: cache
uses: actions/cache@v3
with:
path: "**/node_modules"
key: ${{ runner.os }}-npm-${{ hashFiles('**/package-lock.json') }}-v1
restore-keys: |
${{ runner.os }}-npm-
- name: Install dependencies
if: steps.cache.outputs.cache-hit != 'true'
run: npm install

- name: Run Chromatic
uses: chromaui/action@latest
id: publish_chromatic
with:
workingDir: client
projectToken: ${{ secrets.CHROMATIC_PROJECT_TOKEN }}

- name: Comment on PR
uses: thollander/actions-comment-pull-request@v2
with:
message: "πŸš€ **storybook**: ${{ steps.publish_chromatic.outputs.storybookUrl }}"
33 changes: 33 additions & 0 deletions .github/workflows/pr-issue-close.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
name: Close Issue on PR Merge

on:
pull_request:
types: [closed]

jobs:
close-issue:
if: github.event.pull_request.merged == true
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v3

- name: Extract issue number from PR body
id: extract_issue
run: |
# Fetch PR body
PR_BODY=$(curl -s -H "Authorization: token ${{ secrets.CONFIG_SUBMODULE_TOKEN }}" \
"https://api.github.com/repos/${{ github.repository }}/issues/${{ github.event.pull_request.number }}" \
| jq -r '.body')
# Extract issue number from PR body using regex (customize if needed)
ISSUE_NUMBER=$(echo "$PR_BODY" | grep -oP '#\d+' | head -1 | sed 's/#//')
echo "ISSUE_NUMBER=$ISSUE_NUMBER" >> $GITHUB_ENV
- name: Close associated issue
if: env.ISSUE_NUMBER != ''
run: |
echo "Closing issue #${{ env.ISSUE_NUMBER }}"
curl -s -X PATCH -H "Authorization: token ${{ secrets.CONFIG_SUBMODULE_TOKEN }}" \
-H "Accept: application/vnd.github.v3+json" \
-d '{"state": "closed"}' \
"https://api.github.com/repos/${{ github.repository }}/issues/${{ env.ISSUE_NUMBER }}"
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
# 2024-haeng-dong
# ν–‰λ™λŒ€μž₯λ“€μ˜ 정산을 κ°„νŽΈν•˜κ²ŒπŸ’°ν–‰λ™λŒ€μž₯

![service introduce](https://github.com/user-attachments/assets/9e51f7a3-0326-4c06-8b03-65aca574c10c)
17 changes: 17 additions & 0 deletions client/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
logs
*.log
npm-debug.log*

node_modules
dist

.env.*

*storybook.log
.DS_Store

# Sentry Config File
.env.sentry-build-plugin

storybook-static
*storybook.log
2 changes: 2 additions & 0 deletions client/.npmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
engine-strict = true
legacy-peer-deps = true
12 changes: 12 additions & 0 deletions client/.prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"singleQuote": true,
"trailingComma": "all",
"printWidth": 120,
"tabWidth": 2,
"semi": true,
"arrowParens": "avoid",
"endOfLine": "auto",
"jsxSingleQuote": false,
"bracketSpacing": false,
"proseWrap": "preserve"
}
59 changes: 59 additions & 0 deletions client/.storybook/main.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/** @type { import('@storybook/react-webpack5').StorybookConfig } */
import type {StorybookConfig} from '@storybook/react-webpack5';
import path from 'path';
import TsconfigPathsPlugin from 'tsconfig-paths-webpack-plugin';

const config: StorybookConfig = {
stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],
addons: [
'@storybook/addon-webpack5-compiler-swc',
'@storybook/addon-onboarding',
'@storybook/addon-links',
'@storybook/addon-essentials',
'@chromatic-com/storybook',
'@storybook/addon-interactions',
],
framework: {
name: '@storybook/react-webpack5',
options: {},
},
webpackFinal: async config => {
if (config.resolve) {
config.resolve.alias = {
...config.resolve.alias,
'@apis': path.resolve(__dirname, '../src/apis/'),
'@assets': path.resolve(__dirname, '../src/assets/'),
'@components': path.resolve(__dirname, '../src/components/'),
'@constants': path.resolve(__dirname, '../src/constants/'),
'@hooks': path.resolve(__dirname, '../src/hooks/'),
'@store': path.resolve(__dirname, '../src/store/'),
'@mocks': path.resolve(__dirname, '../src/mocks/'),
'@pages': path.resolve(__dirname, '../src/pages/'),
'@utils': path.resolve(__dirname, '../src/utils/'),
'@errors': path.resolve(__dirname, '../src/errors/'),
'@HDesign': path.resolve(__dirname, '../src/components/Design/'),
'@HDcomponents': path.resolve(__dirname, '../src/components/Design/components/'),
'@HDutils': path.resolve(__dirname, '../src/components/Design/utils/'),
'@token': path.resolve(__dirname, '../src/components/Design/token/'),
'@theme': path.resolve(__dirname, '../src/components/Design/theme/'),
'@layouts': path.resolve(__dirname, '../src/components/Design/layouts/'),
'@type': path.resolve(__dirname, '../src/components/Design/type/'),
};
}

config.module = config.module || {};
config.module.rules = config.module.rules || [];

const imageRule = config.module.rules.find(rule => rule?.['test']?.test('.svg'));
if (imageRule) {
imageRule['exclude'] = /\.svg$/;
}

config.module.rules.push({
test: /\.svg$/,
use: ['@svgr/webpack'],
});
return config;
},
};
export default config;
41 changes: 41 additions & 0 deletions client/.storybook/preview.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/** @jsxImportSource @emotion/react */

import type {Preview} from '@storybook/react';
import {HDesignProvider} from '../src/components/Design';

const preview: Preview = {
parameters: {
controls: {
matchers: {
color: /(background|color)$/i,
date: /Date$/i,
},
},
viewport: {
defaultViewport: {
styles: {
width: '375px',
height: '812px',
},
},
},
backgrounds: {
default: 'gray',
values: [
{
name: 'gray',
value: '#f3f3f3',
},
],
},
},
decorators: [
Story => (
<HDesignProvider>
<Story />
</HDesignProvider>
),
],
};

export default preview;
12 changes: 12 additions & 0 deletions client/cypress.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import {defineConfig} from 'cypress';

export default defineConfig({
e2e: {
baseUrl: 'http://localhost:3000',
viewportWidth: 430,
viewportHeight: 930,
// setupNodeEvents(on, config) {
// // implement node event listeners here
// },
},
});
6 changes: 6 additions & 0 deletions client/cypress/constants/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
const CONSTANTS = {
eventName: 'ν…ŒμŠ€νŠΈ 이벀트',
eventPassword: '1234',
};

export default CONSTANTS;
79 changes: 79 additions & 0 deletions client/cypress/e2e/createEvent.cy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import {ROUTER_URLS} from '@constants/routerUrls';
import CONSTANTS from '../constants/constants';
import RULE from '@constants/rule';

beforeEach(() => {
cy.blockSentry();
cy.blockKakao();
});

describe('Flow: λžœλ”© νŽ˜μ΄μ§€μ—μ„œλΆ€ν„° 이벀트λ₯Ό 생성 μ™„λ£Œν•˜λŠ” flow', () => {
it('λžœλ”©νŽ˜μ΄μ§€μ—μ„œ "μ •μ‚° μ‹œμž‘ν•˜κΈ°" λ²„νŠΌμ„ 눌러 행사 이름 μž…λ ₯ νŽ˜μ΄μ§€λ‘œ 이동해야 ν•œλ‹€.', () => {
cy.visit('/');
cy.get('button').contains('μ •μ‚° μ‹œμž‘ν•˜κΈ°').click();
cy.url().should('include', ROUTER_URLS.createEvent);
});

context('행사 이름 μž…λ ₯ νŽ˜μ΄μ§€', () => {
beforeEach(() => {
cy.visit(ROUTER_URLS.createEvent);
});

it('행사 이름 μž…λ ₯ νŽ˜μ΄μ§€μ—μ„œ input이 포컀싱 λ˜μ–΄ 있고, "λ‹€μŒ" λ²„νŠΌμ΄ λΉ„ν™œμ„±ν™” λ˜μ–΄ μžˆμ–΄μ•Ό ν•œλ‹€.', () => {
cy.get('input').focused();
cy.get('button').contains('λ‹€μŒ').should('have.attr', 'disabled');
});

it('행사 이름이 1자 이상 μž…λ ₯된 경우 "λ‹€μŒ" λ²„νŠΌμ΄ ν™œμ„±ν™” 되고, 값이 μ—†λŠ” 경우 "λ‹€μŒ" λ²„νŠΌμ΄ λΉ„ν™œμ„±ν™” λ˜μ–΄μ•Ό ν•œλ‹€.', () => {
cy.get('input').type(CONSTANTS.eventName);
cy.get('button').contains('λ‹€μŒ').should('not.have.attr', 'disabled');
cy.get('input').clear();
cy.get('input').should('have.value', '');
cy.get('button').contains('λ‹€μŒ').should('have.attr', 'disabled');
});

it('행사 이름을 μž…λ ₯ν•œ ν›„ "λ‹€μŒ" λ²„νŠΌμ„ λˆ„λ₯΄λ©΄ 행사 λΉ„λ°€λ²ˆν˜Έ μ„€μ • ν™”λ©΄μœΌλ‘œ 이동해야 ν•œλ‹€.', () => {
cy.get('input').type(CONSTANTS.eventName);
cy.get('button').contains('λ‹€μŒ').click();

// λ‹€μŒ λ²„νŠΌμ„ ν΄λ¦­ν•˜λ©΄ /create/event κ²½λ‘œκ°€ μ•„λ‹ˆλΌ /create/event/?둜 κ°€λ„€μš”.. κ·Έλž˜μ„œ 일단 μ œκ±°ν•¨.
cy.contains('λΉ„λ°€λ²ˆν˜Έ').should('exist');
});
});

context('행사 λΉ„λ°€λ²ˆν˜Έ μž…λ ₯ νŽ˜μ΄μ§€', () => {
beforeEach(() => {
cy.createEventName(CONSTANTS.eventName);
});

it('행사 λΉ„λ°€λ²ˆν˜Έ μž…λ ₯ νŽ˜μ΄μ§€μ—μ„œ input이 포컀싱 λ˜μ–΄ 있고, "행동 κ°œμ‹œ!" λ²„νŠΌμ΄ λΉ„ν™œμ„±ν™” λ˜μ–΄ μžˆμ–΄μ•Ό ν•œλ‹€.', () => {
cy.get('input').focused();
cy.get('button').contains('행동 κ°œμ‹œ!').should('have.attr', 'disabled');
});

it('행사 λΉ„λ°€λ²ˆν˜Έμ— μˆ«μžκ°€ μ•„λ‹Œ μž…λ ₯을 ν•  경우 값이 μž…λ ₯λ˜μ§€ μ•Šμ•„μ•Ό ν•œλ‹€.', () => {
cy.get('input').type('ν…ŒμŠ€νŠΈ');
cy.get('input').should('have.value', '');
});

it(`행사 λΉ„λ°€λ²ˆν˜Έμ— ${RULE.maxEventPasswordLength}자리 이상 μž…λ ₯을 ν•  경우 처음 ${RULE.maxEventPasswordLength}자리만 μž…λ ₯λ˜μ–΄μ•Ό ν•œλ‹€.`, () => {
cy.get('input').type('12345');
cy.get('input').should('have.value', CONSTANTS.eventPassword);
});

it('행사 λΉ„λ°€λ²ˆν˜Έμ΄ 1자 이상 μž…λ ₯된 경우 "행동 κ°œμ‹œ!" λ²„νŠΌμ΄ ν™œμ„±ν™” 되고, 값이 μ—†λŠ” 경우 "행동 κ°œμ‹œ!" λ²„νŠΌμ΄ λΉ„ν™œμ„±ν™” λ˜μ–΄μ•Ό ν•œλ‹€.', () => {
cy.get('input').type(CONSTANTS.eventPassword);
cy.get('button').contains('행동 κ°œμ‹œ!').should('not.have.attr', 'disabled');
cy.get('input').clear();
cy.get('input').should('have.value', '');
cy.get('button').contains('행동 κ°œμ‹œ!').should('have.attr', 'disabled');
});

it('행사 λΉ„λ°€λ²ˆν˜Έμ„ μž…λ ₯ν•œ ν›„ "행동 κ°œμ‹œ!" λ²„νŠΌμ„ λˆ„λ₯΄λ©΄ 행사 생성 μ™„λ£Œ ν™”λ©΄μœΌλ‘œ 이동해야 ν•œλ‹€.', () => {
cy.interceptAPI({type: 'postEvent', statusCode: 200});
cy.interceptAPI({type: 'getEventName', statusCode: 200});
cy.get('input').type(CONSTANTS.eventPassword);
cy.get('button').contains('행동 κ°œμ‹œ!').click();
});
});
});
3 changes: 3 additions & 0 deletions client/cypress/fixtures/postEvent.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"eventId": "550e8400-e29b-41d4-a716-446655440000"
}
Loading

0 comments on commit 50cf06a

Please sign in to comment.