Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .github/workflows/ios-deploy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ jobs:
APP_STORE_CONNECT_API_KEY_CONTENT: ${{ secrets.APP_STORE_CONNECT_API_KEY_CONTENT }}
APP_STORE_CONNECT_API_KEY_IS_KEY_CONTENT_BASE64: ${{ secrets.APP_STORE_CONNECT_API_KEY_IS_KEY_CONTENT_BASE64 }}
TUIST_CONFIG_TOKEN: ${{ secrets.TUIST_TOKEN }}
# 배포 아카이브만 외부 의존성을 정적으로 링크한다.
# 중첩 Frameworks/libswift_*.dylib 로 인한 업로드 거부를 막기 위한 것이고,
# 이 플래그가 없는 빌드는 동적으로 링크돼 커버리지 계측이 붙는다.
TUIST_RELEASE_BUILD: '1'
LANG: en_US.UTF-8
LC_ALL: en_US.UTF-8
FASTLANE_SKIP_UPDATE_CHECK: '1'
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/ios-pr-coverage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -486,6 +486,7 @@ jobs:
uses: actions/github-script@v7
env:
RESULT_BUNDLE_DIR: Artifacts/tests
COVERAGE_SHARD_IDS: ${{ join(fromJSON(needs.build-test-shards.outputs.matrix).shard, ',') }}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Guard the shard matrix before parsing it

When build-test-shards fails before the Tuist command writes its matrix output—for example during setup, dependency installation, or compilation—this job still runs because its job-level condition accepts failed builds, but this expression evaluates fromJSON('') and fails before ios-test-report.js can execute. Consequently, the PR receives no diagnostic report for the build failures the reporter is intended to render; default an absent matrix to an empty shard list before parsing it.

Useful? React with 👍 / 👎.

TEST_OUTCOME: ${{ needs.build-test-shards.result == 'success' && needs.test-shards.result == 'success' && 'success' || 'failure' }}
TEST_RUN_REPORT_PATH: Artifacts/tests
BUILD_RUN_REPORT_PATH: Artifacts/bundle/BuildRunReport.json
Expand Down
13 changes: 11 additions & 2 deletions .maestro/config.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
# Maestro 워크스페이스 설정. 이 디렉토리(.maestro)를 워크스페이스로 연다.
# ** 는 중간 디렉토리가 있어야 매칭되므로 flows 바로 아래 파일용 패턴을 함께 둔다.
#
# 워크스페이스 실행 대상은 엔트리포인트 두 개뿐이다.
# flows/full_test.yaml — 스플래시·로그인부터 전체 순회
# flows/smoke_test.yaml — 짧은 확인용
#
# 하위 디렉토리 플로우(member/home_smoke.yaml, member/vote_team_select.yaml,
# login/google_management.yaml, _shared/switch_section.yaml 등)는 단독으로 돌 수 없다.
# 로그인된 상태를 전제하거나(clearState: false) env 로 ID 를 받는 헬퍼이기 때문이다.
# flows/**/*.yaml 로 싸잡으면 이것들이 워크스페이스 플로우 목록에 떠서
# 로그인 없이 실행되고 member.home.root 를 기다리다 타임아웃으로 죽는다.
# 그래서 글롭을 flows 바로 아래로 제한하고, 나머지는 runFlow: file: 로만 부른다.
flows:
- "flows/*.yaml"
- "flows/**/*.yaml"
31 changes: 31 additions & 0 deletions .maestro/flows/_shared/ensure_management_home.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# 하위 플로우의 로그인 선행조건.
# Maestro Studio 는 워크스페이스 config 의 flows 패턴과 무관하게 모든 플로우 파일을
# 목록에 띄우므로, 각 플로우가 단독 실행돼도 스스로 로그인 상태를 만들 수 있어야 한다.
#
# 이미 홈이면 로그인을 건너뛰므로 full_test 처럼 앞서 로그인한 경우엔 비용이 거의 없다.
appId: io.DDD.Attendance
name: 운영진 홈 보장
tags:
- e2e
- shared
---
- launchApp:
clearState: false

# 스플래시가 끝나 홈이든 로그인 화면이든 확정될 때까지 기다린다.
# id 는 정규식으로 매칭되므로 둘 중 먼저 뜨는 쪽에서 풀린다.
- extendedWaitUntil:
visible:
id: "management.staff.root|auth.login.root"
timeout: 60000

- runFlow:
when:
notVisible:
id: "management.staff.root"
file: ../management/login_to_home.yaml

- extendedWaitUntil:
visible:
id: "management.staff.root"
timeout: 60000
31 changes: 31 additions & 0 deletions .maestro/flows/_shared/ensure_member_home.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# 하위 플로우의 로그인 선행조건.
# Maestro Studio 는 워크스페이스 config 의 flows 패턴과 무관하게 모든 플로우 파일을
# 목록에 띄우므로, 각 플로우가 단독 실행돼도 스스로 로그인 상태를 만들 수 있어야 한다.
#
# 이미 홈이면 로그인을 건너뛰므로 full_test 처럼 앞서 로그인한 경우엔 비용이 거의 없다.
appId: io.DDD.Attendance
name: 멤버 홈 보장
tags:
- e2e
- shared
---
- launchApp:
clearState: false

# 스플래시가 끝나 홈이든 로그인 화면이든 확정될 때까지 기다린다.
# id 는 정규식으로 매칭되므로 둘 중 먼저 뜨는 쪽에서 풀린다.
- extendedWaitUntil:
visible:
id: "member.home.root|auth.login.root"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Handle the opposite role before waiting for member home

When this flow runs after an operations flow, clearState: false preserves the staff login and the app launches at management.staff.root. This wait accepts only the member home or login screen, so it times out before the conditional login_to_home flow can clear state and switch accounts; the newly added standalone guarantee therefore fails in a normal cross-role Studio sequence. Include the opposite-role root in the readiness condition; the management helper has the mirrored issue when a member is logged in.

Useful? React with 👍 / 👎.

timeout: 60000

- runFlow:
when:
notVisible:
id: "member.home.root"
file: ../member/login_to_home.yaml

- extendedWaitUntil:
visible:
id: "member.home.root"
timeout: 60000
27 changes: 27 additions & 0 deletions .maestro/flows/_shared/ensure_profile_main.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# 프로필 화면 선행조건.
# profile/* 와 onboarding/invite_code 는 프로필 화면이 열려 있어야 도는데,
# Maestro Studio 는 모든 플로우 파일을 단독 실행할 수 있게 띄우므로
# 각 플로우가 스스로 이 상태를 만들 수 있어야 한다.
#
# 이미 프로필 화면이면 아무것도 하지 않는다.
appId: io.DDD.Attendance
name: 프로필 화면 보장
tags:
- e2e
- shared
---
- runFlow:
when:
notVisible:
id: "profile.main.root"
commands:
# 운영진 홈까지 확보한 뒤 우측 상단 프로필 버튼으로 들어간다.
- runFlow:
file: ensure_management_home.yaml
- tapOn:
id: "management.staff.profilebutton"

- extendedWaitUntil:
visible:
id: "profile.main.root"
timeout: 30000
12 changes: 12 additions & 0 deletions .maestro/flows/login/google.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,15 @@ name: Google 로그인 시작
- tapOn:
text: "Continue|계속"
optional: true

# 여기부터는 앱이 아니라 SafariViewService 위다.
# accounts.google.com 콜드 로딩이 30초를 넘기는 일이 있다.
# (실패 녹화 30.7초 지점에 "잠시만 기다려 주세요..." 스피너가 아직 떠 있었고
# 32초에 타임아웃으로 웹뷰가 닫혔다.)
# 그래서 로딩이 끝나는 것을 먼저 기다린 뒤 계정 화면을 확인한다.
- extendedWaitUntil:
notVisible: ".*잠시만 기다려 주세요.*|.*Just a moment.*"
timeout: 90000
Comment on lines +19 to +21

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Wait for positive Google page readiness

When SafariViewService initially displays a blank page or has not yet inserted the loading text after the optional Continue tap, this notVisible condition is already satisfied and returns immediately, so the advertised 90-second cold-load wait is bypassed. The role-specific callers then wait only 60 seconds for an account row, meaning a page that takes longer still times out; wait for a positive readiness signal or first establish that the loading indicator appeared before waiting for it to disappear.

Useful? React with 👍 / 👎.

# 계정 선택 화면의 제목("계정을 선택하세요.")은 Google 이 여러 요소로 쪼개 렌더할 수 있어
# 통째로 매칭되지 않는다. 그래서 제목이 아니라 실제로 탭할 계정 행을 호출 측에서 기다린다.
- takeScreenshot: .maestro/artifacts/login/google-auth-page
5 changes: 3 additions & 2 deletions .maestro/flows/login/google_management.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@ name: Google 운영진 계정 로그인
file: google.yaml

# suhwj81이 포함된 계정은 운영진 계정이다.
# 제목 대신 탭 대상인 계정 행이 뜨는 것을 기다린다.
- extendedWaitUntil:
visible: ".*계정(을)? 선택(하세요)?[.]*|.*Choose an account.*"
timeout: 30000
visible: ".*suhwj81.*"
timeout: 60000
- tapOn:
text: ".*suhwj81.*"
- tapOn:
Expand Down
5 changes: 3 additions & 2 deletions .maestro/flows/login/google_member.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,10 @@ name: Google 멤버 계정 로그인
file: google.yaml

# 멤버 계정은 suhwj81 운영진 계정 바로 아래에 표시된다.
# 제목 대신 탭 대상인 계정 행이 뜨는 것을 기다린다.
- extendedWaitUntil:
visible: ".*계정(을)? 선택(하세요)?[.]*|.*Choose an account.*"
timeout: 30000
visible: ".*suhwj81.*"
timeout: 60000
- tapOn:
text: ".*@.*"
below:
Expand Down
3 changes: 3 additions & 0 deletions .maestro/flows/management/attendance_refresh.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ tags:
- management
- attendance
---
# 단독 실행돼도 돌 수 있게 로그인 상태를 먼저 보장한다.
- runFlow:
file: ../_shared/ensure_management_home.yaml

- extendedWaitUntil:
visible:
Expand Down
4 changes: 4 additions & 0 deletions .maestro/flows/management/home_smoke.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ tags:
- e2e
- management
---
# 단독 실행돼도 돌 수 있게 로그인 상태를 먼저 보장한다.
- runFlow:
file: ../_shared/ensure_management_home.yaml

- extendedWaitUntil:
visible:
id: "management.staff.root"
Expand Down
3 changes: 3 additions & 0 deletions .maestro/flows/management/qr_scanner.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ tags:
- management
- qr
---
# 단독 실행돼도 돌 수 있게 로그인 상태를 먼저 보장한다.
- runFlow:
file: ../_shared/ensure_management_home.yaml

- extendedWaitUntil:
visible:
Expand Down
3 changes: 3 additions & 0 deletions .maestro/flows/management/schedule_change.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ tags:
- management
- schedule
---
# 단독 실행돼도 돌 수 있게 로그인 상태를 먼저 보장한다.
- runFlow:
file: ../_shared/ensure_management_home.yaml

- extendedWaitUntil:
visible:
Expand Down
3 changes: 3 additions & 0 deletions .maestro/flows/management/schedule_tab.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ tags:
- management
- schedule
---
# 단독 실행돼도 돌 수 있게 로그인 상태를 먼저 보장한다.
- runFlow:
file: ../_shared/ensure_management_home.yaml

- extendedWaitUntil:
visible:
Expand Down
3 changes: 3 additions & 0 deletions .maestro/flows/management/team_switch.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ tags:
- management
- attendance
---
# 단독 실행돼도 돌 수 있게 로그인 상태를 먼저 보장한다.
- runFlow:
file: ../_shared/ensure_management_home.yaml

- extendedWaitUntil:
visible:
Expand Down
3 changes: 3 additions & 0 deletions .maestro/flows/management/vote_tab.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ tags:
- management
- vote
---
# 단독 실행돼도 돌 수 있게 로그인 상태를 먼저 보장한다.
- runFlow:
file: ../_shared/ensure_management_home.yaml

- extendedWaitUntil:
visible:
Expand Down
6 changes: 4 additions & 2 deletions .maestro/flows/member/home_smoke.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@ tags:
- e2e
- member
---
- launchApp:
clearState: false
# 단독 실행돼도 돌 수 있게 로그인 상태를 먼저 보장한다.
- runFlow:
file: ../_shared/ensure_member_home.yaml

- extendedWaitUntil:
visible:
id: "member.home.root"
Expand Down
3 changes: 3 additions & 0 deletions .maestro/flows/member/qr_code.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ tags:
- member
- qr
---
# 단독 실행돼도 돌 수 있게 로그인 상태를 먼저 보장한다.
- runFlow:
file: ../_shared/ensure_member_home.yaml

- extendedWaitUntil:
visible:
Expand Down
3 changes: 3 additions & 0 deletions .maestro/flows/member/schedule_list.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ tags:
- member
- schedule
---
# 단독 실행돼도 돌 수 있게 로그인 상태를 먼저 보장한다.
- runFlow:
file: ../_shared/ensure_member_home.yaml

- extendedWaitUntil:
visible:
Expand Down
3 changes: 3 additions & 0 deletions .maestro/flows/member/vote.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ tags:
- member
- vote
---
# 단독 실행돼도 돌 수 있게 로그인 상태를 먼저 보장한다.
- runFlow:
file: ../_shared/ensure_member_home.yaml

- extendedWaitUntil:
visible:
Expand Down
3 changes: 3 additions & 0 deletions .maestro/flows/member/vote_feedback.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ tags:
- member
- vote
---
# 단독 실행돼도 돌 수 있게 로그인 상태를 먼저 보장한다.
- runFlow:
file: ../_shared/ensure_member_home.yaml

- extendedWaitUntil:
visible:
Expand Down
3 changes: 3 additions & 0 deletions .maestro/flows/member/vote_team_select.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ tags:
- member
- vote
---
# 단독 실행돼도 돌 수 있게 로그인 상태를 먼저 보장한다.
- runFlow:
file: ../_shared/ensure_member_home.yaml

- extendedWaitUntil:
visible:
Expand Down
3 changes: 3 additions & 0 deletions .maestro/flows/onboarding/invite_code.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ tags:
- e2e
- onboarding
---
# 단독 실행돼도 돌 수 있게 선행 상태를 먼저 보장한다.
- runFlow:
file: ../_shared/ensure_profile_main.yaml

- extendedWaitUntil:
visible:
Expand Down
3 changes: 3 additions & 0 deletions .maestro/flows/profile/create_app.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ tags:
- e2e
- profile
---
# 단독 실행돼도 돌 수 있게 선행 상태를 먼저 보장한다.
- runFlow:
file: ../_shared/ensure_profile_main.yaml

- extendedWaitUntil:
visible:
Expand Down
5 changes: 3 additions & 2 deletions .maestro/flows/profile/home_smoke.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ tags:
- e2e
- profile
---
- launchApp:
clearState: false
# 단독 실행돼도 돌 수 있게 선행 상태를 먼저 보장한다.
- runFlow:
file: ../_shared/ensure_management_home.yaml

# 운영진 홈에서 우측 상단 프로필 버튼으로 들어간다.
- extendedWaitUntil:
Expand Down
3 changes: 3 additions & 0 deletions .maestro/flows/profile/privacy_policy_web.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ tags:
- profile
- web
---
# 단독 실행돼도 돌 수 있게 선행 상태를 먼저 보장한다.
- runFlow:
file: ../_shared/ensure_profile_main.yaml

- extendedWaitUntil:
visible:
Expand Down
3 changes: 3 additions & 0 deletions .maestro/flows/profile/swipe_back.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ tags:
- profile
- navigation
---
# 단독 실행돼도 돌 수 있게 선행 상태를 먼저 보장한다.
- runFlow:
file: ../_shared/ensure_profile_main.yaml

- extendedWaitUntil:
visible:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ struct AttendanceCheckView: View {
selectPartType()

selectPartAttendanceStatus()
.padding(.bottom, 20)
}
.accessibilityElement(children: .contain)
.dddAccessibilityID(ManagementAccessibilityID.Attendance.root)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,10 @@ public struct StaffView: View {
closeDropDown()
}
}
.sheet(item: $store.scope(\.$destination, action: \.destination).qrcode) { qrCodeStore in
.sheet(item: $store.scope(
state: \.destination?.qrcode,
action: \.destination.qrcode
)) { qrCodeStore in
QRScannerView(store: qrCodeStore)
.presentationDetents([.height(UIScreen.screenHeight * 0.85)])
.presentationCornerRadius(20)
Expand Down
5 changes: 4 additions & 1 deletion Projects/Feature/Profile/Sources/Main/View/ProfileView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,10 @@ public struct ProfileView: View {
}
}

.sheet(item: $store.scope(\.$destination, action: \.destination).createApp) { crateAppStore in
.sheet(item: $store.scope(
state: \.destination?.createApp,
action: \.destination.createApp
)) { crateAppStore in
CreateAppView(store: crateAppStore)
.presentationDetents([.height(UIScreen.screenHeight * 0.65)])
.presentationCornerRadius(20)
Expand Down
Loading
Loading