@simplysm/capacitor-plugin-intent 12.16.41

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,98 @@
1
+ # Slice 1: startActivityForResult Android 수동 테스트
2
+
3
+ ## 전제 조건
4
+
5
+ - Capacitor 앱이 Android 디바이스/에뮬레이터에서 실행 중이다
6
+ - `capacitor-plugin-intent`가 플러그인으로 등록되어 있다
7
+
8
+ ## Scenario: action만 지정하여 Activity 시작
9
+
10
+ ### 수행 절차
11
+ 1. `Intent.startActivityForResult({ action: "android.intent.action.PICK" })` 호출
12
+ 2. Android 시스템이 해당 action을 처리할 수 있는 앱 목록을 표시하는지 확인
13
+
14
+ ### 기대 결과
15
+ - 해당 action을 처리하는 Activity가 열린다
16
+
17
+ ## Scenario: action + uri 지정
18
+
19
+ ### 수행 절차
20
+ 1. `Intent.startActivityForResult({ action: "android.intent.action.VIEW", uri: "content://contacts/people/1" })` 호출
21
+
22
+ ### 기대 결과
23
+ - Intent의 data에 해당 URI가 설정되어 Activity가 열린다
24
+
25
+ ## Scenario: extras 지정
26
+
27
+ ### 수행 절차
28
+ 1. `Intent.startActivityForResult({ action: "com.example.ACTION", extras: { "key": "value" } })` 호출
29
+
30
+ ### 기대 결과
31
+ - Intent의 extra에 해당 데이터가 포함되어 Activity가 열린다
32
+
33
+ ## Scenario: package + component로 명시적 Activity 지정
34
+
35
+ ### 수행 절차
36
+ 1. 대상 앱의 패키지명과 Activity 클래스명을 확인
37
+ 2. `Intent.startActivityForResult({ action: "android.intent.action.MAIN", package: "com.example.app", component: "com.example.app.MainActivity" })` 호출
38
+
39
+ ### 기대 결과
40
+ - 지정된 패키지의 지정된 Activity가 직접 열린다
41
+
42
+ ## Scenario: type(MIME type) 지정
43
+
44
+ ### 수행 절차
45
+ 1. `Intent.startActivityForResult({ action: "android.intent.action.GET_CONTENT", type: "image/*" })` 호출
46
+
47
+ ### 기대 결과
48
+ - Intent의 MIME type이 설정되어 이미지 선택 Activity가 열린다
49
+
50
+ ## Scenario: uri + type 동시 지정
51
+
52
+ ### 수행 절차
53
+ 1. `Intent.startActivityForResult({ action: "android.intent.action.VIEW", uri: "content://media/images", type: "image/png" })` 호출
54
+
55
+ ### 기대 결과
56
+ - Intent에 setDataAndType으로 URI와 MIME type이 함께 설정된다
57
+
58
+ ## Scenario: 대상 Activity가 RESULT_OK로 종료
59
+
60
+ ### 수행 절차
61
+ 1. `Intent.startActivityForResult({ action: "android.intent.action.GET_CONTENT", type: "image/*" })` 호출
62
+ 2. 열린 Activity에서 이미지를 선택
63
+
64
+ ### 기대 결과
65
+ - Promise가 resolve되고 `{ resultCode: -1, data: "content://...", extras: {...} }` 형태의 결과를 반환한다
66
+
67
+ ## Scenario: 대상 Activity가 RESULT_CANCELED로 종료 (사용자 뒤로가기)
68
+
69
+ ### 수행 절차
70
+ 1. `Intent.startActivityForResult({ action: "android.intent.action.GET_CONTENT", type: "image/*" })` 호출
71
+ 2. 열린 Activity에서 뒤로가기 버튼 누름
72
+
73
+ ### 기대 결과
74
+ - Promise가 resolve되고 `{ resultCode: 0 }`을 반환한다
75
+
76
+ ## Scenario: 대상 Activity가 data 없이 종료
77
+
78
+ ### 수행 절차
79
+ 1. data를 반환하지 않는 Activity를 시작하고 정상 완료
80
+
81
+ ### 기대 결과
82
+ - 반환값의 `data` 필드는 undefined이다
83
+
84
+ ## Scenario: 대상 Activity가 extras 없이 종료
85
+
86
+ ### 수행 절차
87
+ 1. extras를 반환하지 않는 Activity를 시작하고 정상 완료
88
+
89
+ ### 기대 결과
90
+ - 반환값의 `extras` 필드는 undefined이다
91
+
92
+ ## Scenario: 존재하지 않는 앱으로 Activity 시작 시도
93
+
94
+ ### 수행 절차
95
+ 1. `Intent.startActivityForResult({ action: "android.intent.action.MAIN", package: "com.nonexistent.app", component: "com.nonexistent.app.MainActivity" })` 호출
96
+
97
+ ### 기대 결과
98
+ - ActivityNotFoundException이 발생하여 Promise가 reject된다
@@ -0,0 +1,40 @@
1
+ import { resolve } from "path";
2
+
3
+ const pkgRoot = resolve(import.meta.dirname, "..");
4
+ const srcDir = resolve(pkgRoot, "src");
5
+
6
+ describe("Slice 1: startActivityForResult TypeScript 인터페이스", () => {
7
+ test("IIntentPlugin에 startActivityForResult 메서드가 정의되어 있다", async () => {
8
+ const mod = await import(resolve(srcDir, "IIntentPlugin.ts"));
9
+
10
+ // IStartActivityForResultOptions 타입이 export되어야 한다
11
+ expect(mod.IStartActivityForResultOptions).toBeUndefined; // interface는 런타임에 없지만 export 확인
12
+
13
+ // IActivityResult 타입이 export되어야 한다
14
+ expect(mod.IActivityResult).toBeUndefined;
15
+ });
16
+
17
+ test("IStartActivityForResultOptions에 필수 필드 action과 선택 필드들이 정의되어 있다", async () => {
18
+ const content = (await import("fs")).readFileSync(resolve(srcDir, "IIntentPlugin.ts"), "utf-8");
19
+ expect(content).toContain("interface IStartActivityForResultOptions");
20
+ expect(content).toMatch(/action\s*:\s*string/);
21
+ expect(content).toMatch(/uri\?\s*:\s*string/);
22
+ expect(content).toMatch(/extras\?\s*:\s*Record<string,\s*unknown>/);
23
+ expect(content).toMatch(/package\?\s*:\s*string/);
24
+ expect(content).toMatch(/component\?\s*:\s*string/);
25
+ expect(content).toMatch(/type\?\s*:\s*string/);
26
+ });
27
+
28
+ test("IActivityResult에 resultCode, data?, extras? 필드가 정의되어 있다", async () => {
29
+ const content = (await import("fs")).readFileSync(resolve(srcDir, "IIntentPlugin.ts"), "utf-8");
30
+ expect(content).toContain("interface IActivityResult");
31
+ expect(content).toMatch(/resultCode\s*:\s*number/);
32
+ expect(content).toMatch(/data\?\s*:\s*string/);
33
+ expect(content).toMatch(/extras\?\s*:\s*Record<string,\s*unknown>/);
34
+ });
35
+
36
+ test("IIntentPlugin.startActivityForResult 메서드 시그니처가 올바르다", async () => {
37
+ const content = (await import("fs")).readFileSync(resolve(srcDir, "IIntentPlugin.ts"), "utf-8");
38
+ expect(content).toMatch(/startActivityForResult\s*\(\s*options\s*:\s*IStartActivityForResultOptions\s*\)\s*:\s*Promise<IActivityResult>/);
39
+ });
40
+ });
@@ -0,0 +1,34 @@
1
+ import { resolve } from "path";
2
+
3
+ const pkgRoot = resolve(import.meta.dirname, "..");
4
+ const srcDir = resolve(pkgRoot, "src");
5
+
6
+ describe("Slice 2: startActivityForResult TypeScript 래퍼 및 웹 stub", () => {
7
+ // Scenario: Intent.startActivityForResult static 메서드 존재
8
+ test("Intent.startActivityForResult static 메서드가 존재한다", async () => {
9
+ const mod = await import(resolve(srcDir, "Intent.ts"));
10
+ expect(typeof mod.Intent.startActivityForResult).toBe("function");
11
+ });
12
+
13
+ // Scenario: 웹에서 startActivityForResult 호출
14
+ test("IntentWeb.startActivityForResult가 resultCode 0으로 resolve한다", async () => {
15
+ const mod = await import(resolve(srcDir, "web/IntentWeb.ts"));
16
+ const web = new mod.IntentWeb();
17
+
18
+ // alert를 mock
19
+ globalThis.alert = vi.fn();
20
+
21
+ const result = await web.startActivityForResult({ action: "test.ACTION" });
22
+ expect(result).toEqual({ resultCode: 0 });
23
+ expect(globalThis.alert).toHaveBeenCalledWith(
24
+ "[Intent] 웹 환경에서는 startActivityForResult를 지원하지 않습니다.",
25
+ );
26
+ });
27
+
28
+ // index.ts에서 새 타입이 export되는지 확인
29
+ test("index.ts에서 IStartActivityForResultOptions, IActivityResult가 re-export된다", async () => {
30
+ const content = (await import("fs")).readFileSync(resolve(srcDir, "IIntentPlugin.ts"), "utf-8");
31
+ expect(content).toContain("export interface IStartActivityForResultOptions");
32
+ expect(content).toContain("export interface IActivityResult");
33
+ });
34
+ });
package/tsconfig.json ADDED
@@ -0,0 +1,8 @@
1
+ {
2
+ "extends": "../../tsconfig.base.json",
3
+ "compilerOptions": {
4
+ "lib": ["ES2021", "DOM"],
5
+ "outDir": "./dist"
6
+ },
7
+ "exclude": ["dist", "node_modules"]
8
+ }