@@ -7,6 +7,59 @@ import { execSync } from "child_process";
77
88type Language = "ts" | "js" ;
99
10+ function getSearchDirs ( cwd : string ) : string [ ] {
11+ const dirs = [ cwd ] ;
12+ const basename = path . basename ( cwd ) . toLowerCase ( ) ;
13+ if ( basename === "test" || basename === "tests" ) {
14+ dirs . push ( path . dirname ( cwd ) ) ;
15+ }
16+ return dirs ;
17+ }
18+
19+ function detectIosBundleId ( dirs : string [ ] ) : string | undefined {
20+ for ( const dir of dirs ) {
21+ const entries = fs . readdirSync ( dir ) ;
22+ for ( const entry of entries ) {
23+ if ( entry . endsWith ( ".xcodeproj" ) ) {
24+ const pbxprojPath = path . join ( dir , entry , "project.pbxproj" ) ;
25+ if ( fs . existsSync ( pbxprojPath ) ) {
26+ const content = fs . readFileSync ( pbxprojPath , "utf-8" ) ;
27+ const match = content . match ( / P R O D U C T _ B U N D L E _ I D E N T I F I E R \s * = \s * " ? ( [ ^ " ; ] + ) " ? \s * ; / ) ;
28+ if ( match ) {
29+ return match [ 1 ] . trim ( ) ;
30+ }
31+ }
32+ }
33+ }
34+ }
35+ return undefined ;
36+ }
37+
38+ function detectAndroidPackageName ( dirs : string [ ] ) : string | undefined {
39+ for ( const dir of dirs ) {
40+ const appDir = path . join ( dir , "app" ) ;
41+ if ( ! fs . existsSync ( appDir ) ) continue ;
42+
43+ for ( const filename of [ "build.gradle.kts" , "build.gradle" ] ) {
44+ const gradlePath = path . join ( appDir , filename ) ;
45+ if ( ! fs . existsSync ( gradlePath ) ) continue ;
46+
47+ const content = fs . readFileSync ( gradlePath , "utf-8" ) ;
48+ const appIdMatch = content . match ( / a p p l i c a t i o n I d \s * = ? \s * " ( [ ^ " ] + ) " / ) ;
49+ if ( appIdMatch ) return appIdMatch [ 1 ] ;
50+
51+ const namespaceMatch = content . match ( / n a m e s p a c e \s * = ? \s * " ( [ ^ " ] + ) " / ) ;
52+ if ( namespaceMatch ) return namespaceMatch [ 1 ] ;
53+ }
54+ }
55+ return undefined ;
56+ }
57+
58+ function detectBundleId ( ) : string {
59+ const dirs = getSearchDirs ( process . cwd ( ) ) ;
60+ return detectIosBundleId ( dirs ) ?? detectAndroidPackageName ( dirs ) ?? "" ;
61+ }
62+
1063function createPackageJson ( targetDir : string , language : Language ) : void {
1164 const pkgPath = path . join ( targetDir , "package.json" ) ;
1265
@@ -32,7 +85,7 @@ function createPackageJson(targetDir: string, language: Language): void {
3285 fs . writeFileSync ( pkgPath , JSON . stringify ( pkg , null , 2 ) + "\n" ) ;
3386}
3487
35- function createConfigFile ( targetDir : string , testDir : string , language : Language ) : void {
88+ function createConfigFile ( targetDir : string , testDir : string , language : Language , bundleId : string ) : void {
3689 const ext = language === "ts" ? "ts" : "js" ;
3790 const configPath = path . join ( targetDir , `mobilewright.config.${ ext } ` ) ;
3891
@@ -44,9 +97,11 @@ function createConfigFile(targetDir: string, testDir: string, language: Language
4497 ? "export default defineConfig"
4598 : "module.exports = defineConfig" ;
4699
100+ const bundleIdLine = bundleId ? `\n bundleId: '${ bundleId } ',` : "" ;
101+
47102 const content = `${ importLine }
48103${ exportLine } ({
49- testDir: './${ testDir } ',
104+ testDir: './${ testDir } ',${ bundleIdLine }
50105 reporter: 'html',
51106});
52107` ;
@@ -64,8 +119,6 @@ function createTestFile(targetDir: string, testDir: string, language: Language):
64119
65120 const content = `${ importLine }
66121
67- test.use({ bundleId: "com.example.app" });
68-
69122test('app launches and shows home screen', async ({ screen }) => {
70123 await expect(screen.getByText('Welcome')).toBeVisible();
71124});
@@ -92,6 +145,8 @@ async function main() {
92145 "Getting started with writing mobile automation and end-to-end tests"
93146 ) ;
94147
148+ const detectedBundleId = detectBundleId ( ) ;
149+
95150 const response = await prompts (
96151 [
97152 {
@@ -110,6 +165,12 @@ async function main() {
110165 message : "Directory name for test files?" ,
111166 initial : "tests" ,
112167 } ,
168+ {
169+ type : "text" ,
170+ name : "bundleId" ,
171+ message : "What is the app bundle ID to test? (Leave empty to skip)" ,
172+ initial : detectedBundleId ,
173+ } ,
113174 ] ,
114175 {
115176 onCancel : ( ) => {
@@ -118,9 +179,10 @@ async function main() {
118179 }
119180 ) ;
120181
121- const { language, testDir } = response as {
182+ const { language, testDir, bundleId } = response as {
122183 language : Language ;
123184 testDir: string ;
185+ bundleId: string ;
124186 } ;
125187
126188 if ( ! language || ! testDir ) {
@@ -130,7 +192,7 @@ async function main() {
130192 const targetDir = process . cwd ( ) ;
131193
132194 createPackageJson ( targetDir , language ) ;
133- createConfigFile ( targetDir , testDir , language ) ;
195+ createConfigFile ( targetDir , testDir , language , bundleId ) ;
134196 createTestFile ( targetDir , testDir , language ) ;
135197
136198 runNpmInstall ( targetDir ) ;
0 commit comments