@tamagui/native-ci 2.0.0-rc.3 → 2.0.0-rc.30
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.
- package/dist/cli.mjs +15 -6
- package/dist/cli.mjs.map +1 -1
- package/dist/detox.mjs +7 -4
- package/dist/detox.mjs.map +1 -1
- package/dist/index.js +9 -95
- package/dist/index.js.map +1 -6
- package/dist/metro.mjs +25 -3
- package/dist/metro.mjs.map +1 -1
- package/package.json +4 -3
- package/src/cli.ts +24 -2
- package/src/detox.ts +10 -1
- package/src/ios.ts +192 -15
- package/src/metro.ts +49 -2
- package/src/run-detox-android.ts +1 -0
- package/src/run-detox-ios.ts +1 -0
- package/types/detox.d.ts +3 -0
- package/types/detox.d.ts.map +1 -1
- package/types/ios.d.ts +29 -0
- package/types/ios.d.ts.map +1 -1
- package/types/metro.d.ts.map +1 -1
- package/dist/cache.js +0 -71
- package/dist/cache.js.map +0 -6
- package/dist/cli.js +0 -298
- package/dist/cli.js.map +0 -6
- package/dist/constants.js +0 -12
- package/dist/constants.js.map +0 -6
- package/dist/deps.js +0 -44
- package/dist/deps.js.map +0 -6
- package/dist/detox.js +0 -73
- package/dist/detox.js.map +0 -6
- package/dist/fingerprint.js +0 -43
- package/dist/fingerprint.js.map +0 -6
- package/dist/metro.js +0 -102
- package/dist/metro.js.map +0 -6
- package/dist/runner.js +0 -73
- package/dist/runner.js.map +0 -6
package/src/ios.ts
CHANGED
|
@@ -9,6 +9,187 @@ import { $ } from 'bun'
|
|
|
9
9
|
import { isCI } from './runner'
|
|
10
10
|
import { generateFingerprint } from './fingerprint'
|
|
11
11
|
|
|
12
|
+
/**
|
|
13
|
+
* Check if any iOS simulator is booted and available for testing.
|
|
14
|
+
* Returns true if at least one simulator is booted.
|
|
15
|
+
*/
|
|
16
|
+
export function hasBootedSimulator(): boolean {
|
|
17
|
+
return !!getBootedSimulatorUDID()
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Get the UDID of the first booted iOS simulator, or null if none.
|
|
22
|
+
*/
|
|
23
|
+
export function getBootedSimulatorUDID(): string | null {
|
|
24
|
+
try {
|
|
25
|
+
const output = execSync('xcrun simctl list devices booted', {
|
|
26
|
+
encoding: 'utf-8',
|
|
27
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
28
|
+
})
|
|
29
|
+
const match = output.match(/\(([A-F0-9-]{36})\)/i)
|
|
30
|
+
return match ? match[1] : null
|
|
31
|
+
} catch {
|
|
32
|
+
return null
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Boot an iOS simulator. Picks the first available iPhone device.
|
|
38
|
+
*/
|
|
39
|
+
export function ensureBootedSimulator(): void {
|
|
40
|
+
if (hasBootedSimulator()) return
|
|
41
|
+
|
|
42
|
+
console.info('No booted iOS simulator found, booting one...')
|
|
43
|
+
try {
|
|
44
|
+
const output = execSync('xcrun simctl list devices available', {
|
|
45
|
+
encoding: 'utf-8',
|
|
46
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
47
|
+
})
|
|
48
|
+
// find first available iPhone
|
|
49
|
+
const match = output.match(/iPhone[^\n]*\(([A-F0-9-]{36})\)/i)
|
|
50
|
+
if (!match) {
|
|
51
|
+
throw new Error('No available iPhone simulator found. Install one via Xcode.')
|
|
52
|
+
}
|
|
53
|
+
const udid = match[1]
|
|
54
|
+
console.info(`Booting simulator ${udid}...`)
|
|
55
|
+
execSync(`xcrun simctl boot ${udid}`, { stdio: 'inherit' })
|
|
56
|
+
console.info('Simulator booted.')
|
|
57
|
+
} catch (err) {
|
|
58
|
+
throw new Error(
|
|
59
|
+
`Failed to boot iOS simulator: ${err instanceof Error ? err.message : err}`
|
|
60
|
+
)
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Check if an app is installed on the booted simulator.
|
|
66
|
+
*/
|
|
67
|
+
function isAppInstalled(bundleId: string, udid: string): boolean {
|
|
68
|
+
try {
|
|
69
|
+
execSync(`xcrun simctl get_app_container "${udid}" "${bundleId}"`, {
|
|
70
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
71
|
+
})
|
|
72
|
+
return true
|
|
73
|
+
} catch {
|
|
74
|
+
return false
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Ensure the app is installed on a specific simulator.
|
|
80
|
+
* For dev client apps, builds if needed then installs.
|
|
81
|
+
* For Expo Go apps, ensures Expo Go is present.
|
|
82
|
+
*/
|
|
83
|
+
export async function ensureAppInstalled(opts: {
|
|
84
|
+
projectRoot: string
|
|
85
|
+
bundleId: string
|
|
86
|
+
udid?: string
|
|
87
|
+
}): Promise<void> {
|
|
88
|
+
const { projectRoot, bundleId } = opts
|
|
89
|
+
const udid = opts.udid || getBootedSimulatorUDID() || 'booted'
|
|
90
|
+
|
|
91
|
+
// check if app is already installed
|
|
92
|
+
if (isAppInstalled(bundleId, udid)) {
|
|
93
|
+
console.info(`App ${bundleId} already installed on simulator ${udid}`)
|
|
94
|
+
return
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
if (bundleId === 'host.exp.Exponent') {
|
|
98
|
+
await installExpoGo(udid)
|
|
99
|
+
return
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// custom dev client - build and install
|
|
103
|
+
console.info(`App ${bundleId} not installed, building...`)
|
|
104
|
+
await ensureIOSFolder()
|
|
105
|
+
|
|
106
|
+
const appPath =
|
|
107
|
+
process.env.DETOX_IOS_APP_PATH ||
|
|
108
|
+
'ios/build/Build/Products/Debug-iphonesimulator/tamaguikitchensink.app'
|
|
109
|
+
const fullAppPath = join(projectRoot, appPath)
|
|
110
|
+
|
|
111
|
+
if (!existsSync(fullAppPath)) {
|
|
112
|
+
await ensureIOSApp('ios.sim.debug')
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
console.info(`Installing app on simulator ${udid}...`)
|
|
116
|
+
execSync(`xcrun simctl install "${udid}" "${fullAppPath}"`, { stdio: 'inherit' })
|
|
117
|
+
console.info('App installed.')
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Get the bundle ID needed for maestro tests.
|
|
122
|
+
* Checks flow files first (they declare appId), falls back to app.json.
|
|
123
|
+
*/
|
|
124
|
+
export function getMaestroBundleId(projectRoot: string): string {
|
|
125
|
+
// check flow files for appId
|
|
126
|
+
const flowsDir = join(projectRoot, 'flows')
|
|
127
|
+
if (existsSync(flowsDir)) {
|
|
128
|
+
try {
|
|
129
|
+
const files = require('fs').readdirSync(flowsDir) as string[]
|
|
130
|
+
for (const f of files) {
|
|
131
|
+
if (!f.endsWith('.yaml')) continue
|
|
132
|
+
const content = readFileSync(join(flowsDir, f), 'utf-8')
|
|
133
|
+
const match = content.match(/^appId:\s*(.+)$/m)
|
|
134
|
+
if (match) return match[1].trim()
|
|
135
|
+
}
|
|
136
|
+
} catch {}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// fall back to app.json
|
|
140
|
+
try {
|
|
141
|
+
const appJson = JSON.parse(readFileSync(join(projectRoot, 'app.json'), 'utf-8'))
|
|
142
|
+
return appJson.expo?.ios?.bundleIdentifier || 'host.exp.Exponent'
|
|
143
|
+
} catch {
|
|
144
|
+
return 'host.exp.Exponent'
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Download and install Expo Go on the booted simulator.
|
|
150
|
+
*/
|
|
151
|
+
async function installExpoGo(udid: string): Promise<void> {
|
|
152
|
+
const tmpDir = join(require('os').tmpdir(), 'expo-go-install')
|
|
153
|
+
const appPath = join(tmpDir, 'Expo Go.app')
|
|
154
|
+
|
|
155
|
+
// skip download if already cached
|
|
156
|
+
if (existsSync(appPath)) {
|
|
157
|
+
console.info(`Installing cached Expo Go on simulator ${udid}...`)
|
|
158
|
+
execSync(`xcrun simctl install "${udid}" "${appPath}"`, { stdio: 'inherit' })
|
|
159
|
+
console.info('Expo Go installed.')
|
|
160
|
+
return
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
console.info('Downloading Expo Go...')
|
|
164
|
+
mkdirSync(tmpDir, { recursive: true })
|
|
165
|
+
|
|
166
|
+
// get the download URL from expo's version API
|
|
167
|
+
const { getVersionsAsync } =
|
|
168
|
+
// @ts-ignore - no type declarations for internal expo module
|
|
169
|
+
require('@expo/cli/build/src/api/getVersions') as {
|
|
170
|
+
getVersionsAsync: () => Promise<any>
|
|
171
|
+
}
|
|
172
|
+
const versions = await getVersionsAsync()
|
|
173
|
+
|
|
174
|
+
// find the latest SDK version that has an iOS client URL
|
|
175
|
+
const sdkVersions = Object.entries(versions.sdkVersions || {})
|
|
176
|
+
.filter(([, v]: [string, any]) => v.iosClientUrl)
|
|
177
|
+
.sort(([a], [b]) => b.localeCompare(a, undefined, { numeric: true }))
|
|
178
|
+
const clientUrl = (sdkVersions[0]?.[1] as any)?.iosClientUrl
|
|
179
|
+
|
|
180
|
+
if (!clientUrl) {
|
|
181
|
+
throw new Error('Could not find Expo Go download URL')
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
execSync(`curl -fsSL "${clientUrl}" -o "${tmpDir}/ExpoGo.tar.gz"`, { stdio: 'inherit' })
|
|
185
|
+
// archive contains .app contents directly, extract into .app bundle
|
|
186
|
+
mkdirSync(appPath, { recursive: true })
|
|
187
|
+
execSync(`tar -xzf "${tmpDir}/ExpoGo.tar.gz" -C "${appPath}"`, { stdio: 'inherit' })
|
|
188
|
+
|
|
189
|
+
execSync(`xcrun simctl install "${udid}" "${appPath}"`, { stdio: 'inherit' })
|
|
190
|
+
console.info('Expo Go installed.')
|
|
191
|
+
}
|
|
192
|
+
|
|
12
193
|
/**
|
|
13
194
|
* Shutdown all simulators and clean up zombie simulator processes.
|
|
14
195
|
* macOS doesn't properly clean up simulators between test runs, leading to
|
|
@@ -107,6 +288,7 @@ function saveFingerprintCache(projectRoot: string, cache: FingerprintCache): voi
|
|
|
107
288
|
*
|
|
108
289
|
* IMPORTANT: Fingerprint only changes when NATIVE dependencies change
|
|
109
290
|
* (Podfile, native modules, etc). JS-only changes don't require rebuild.
|
|
291
|
+
* Set SKIP_IOS_REBUILD=1 to skip rebuild even when fingerprint changes.
|
|
110
292
|
*/
|
|
111
293
|
export async function ensureIOSApp(config: string = 'ios.sim.debug'): Promise<void> {
|
|
112
294
|
// On CI, the app is built separately - don't build here
|
|
@@ -153,29 +335,24 @@ export async function ensureIOSApp(config: string = 'ios.sim.debug'): Promise<vo
|
|
|
153
335
|
return
|
|
154
336
|
}
|
|
155
337
|
|
|
156
|
-
//
|
|
157
|
-
// Many fingerprint changes are false positives (timestamp changes, etc)
|
|
338
|
+
// fingerprint changed - rebuild by default since native deps likely changed
|
|
158
339
|
if (cache?.fingerprint) {
|
|
159
340
|
console.info(`\n--- iOS fingerprint changed ---`)
|
|
160
341
|
console.info(`Previous: ${cache.fingerprint.slice(0, 16)}...`)
|
|
161
342
|
console.info(`Current: ${currentFingerprint.slice(0, 16)}...`)
|
|
162
|
-
console.info(`App exists at ${appPath}`)
|
|
163
343
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
344
|
+
if (process.env.SKIP_IOS_REBUILD) {
|
|
345
|
+
console.info('SKIP_IOS_REBUILD set, using existing app')
|
|
346
|
+
saveFingerprintCache(projectRoot, {
|
|
347
|
+
fingerprint: currentFingerprint,
|
|
348
|
+
timestamp: new Date().toISOString(),
|
|
349
|
+
appPath,
|
|
350
|
+
})
|
|
168
351
|
return
|
|
169
352
|
}
|
|
170
353
|
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
console.info('Using existing app (set FORCE_IOS_REBUILD=1 to force rebuild)')
|
|
174
|
-
saveFingerprintCache(projectRoot, {
|
|
175
|
-
fingerprint: currentFingerprint,
|
|
176
|
-
timestamp: new Date().toISOString(),
|
|
177
|
-
appPath,
|
|
178
|
-
})
|
|
354
|
+
console.info('Native dependencies changed, rebuilding...')
|
|
355
|
+
await buildIOSApp(config, projectRoot, appPath, currentFingerprint)
|
|
179
356
|
return
|
|
180
357
|
}
|
|
181
358
|
|
package/src/metro.ts
CHANGED
|
@@ -6,8 +6,10 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import type { Subprocess } from 'bun'
|
|
9
|
+
import { execSync } from 'node:child_process'
|
|
9
10
|
import {
|
|
10
11
|
METRO_URL,
|
|
12
|
+
METRO_PORT,
|
|
11
13
|
DEFAULT_METRO_WAIT_ATTEMPTS,
|
|
12
14
|
DEFAULT_METRO_WAIT_INTERVAL_MS,
|
|
13
15
|
type Platform,
|
|
@@ -93,6 +95,26 @@ export async function prewarmBundle(platform: Platform): Promise<void> {
|
|
|
93
95
|
}
|
|
94
96
|
}
|
|
95
97
|
|
|
98
|
+
/**
|
|
99
|
+
* Detect if the current project uses expo-dev-client by checking package.json.
|
|
100
|
+
*/
|
|
101
|
+
function projectUsesDevClient(): boolean {
|
|
102
|
+
try {
|
|
103
|
+
const pkg = JSON.parse(require('fs').readFileSync('package.json', 'utf-8'))
|
|
104
|
+
const deps = { ...pkg.dependencies, ...pkg.devDependencies }
|
|
105
|
+
// check for expo-dev-client dep, or --dev-client in the start script
|
|
106
|
+
if (deps['expo-dev-client']) return true
|
|
107
|
+
if (
|
|
108
|
+
typeof pkg.scripts?.start === 'string' &&
|
|
109
|
+
pkg.scripts.start.includes('--dev-client')
|
|
110
|
+
)
|
|
111
|
+
return true
|
|
112
|
+
return false
|
|
113
|
+
} catch {
|
|
114
|
+
return false
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
96
118
|
/**
|
|
97
119
|
* Start Metro bundler as a background process.
|
|
98
120
|
*
|
|
@@ -103,7 +125,12 @@ export function startMetro(): MetroProcess {
|
|
|
103
125
|
|
|
104
126
|
// Only clear cache in CI - locally we want fast startup using cached transforms
|
|
105
127
|
const isCI = !!process.env.CI
|
|
106
|
-
const
|
|
128
|
+
const useDevClient = projectUsesDevClient()
|
|
129
|
+
const args = ['bun', 'expo', 'start', '--offline']
|
|
130
|
+
if (useDevClient) {
|
|
131
|
+
args.splice(3, 0, '--dev-client')
|
|
132
|
+
console.info('Dev client detected')
|
|
133
|
+
}
|
|
107
134
|
if (isCI) {
|
|
108
135
|
args.push('--clear')
|
|
109
136
|
console.info('CI detected: clearing Metro cache')
|
|
@@ -167,6 +194,24 @@ async function isMetroRunning(platform: Platform): Promise<boolean> {
|
|
|
167
194
|
}
|
|
168
195
|
}
|
|
169
196
|
|
|
197
|
+
/**
|
|
198
|
+
* Kill whatever process is listening on the Metro port.
|
|
199
|
+
* Prevents conflicts with other projects' Metro instances (or anything else on 8081).
|
|
200
|
+
*/
|
|
201
|
+
function killPortProcess(): void {
|
|
202
|
+
try {
|
|
203
|
+
const pid = execSync(`lsof -ti tcp:${METRO_PORT} -sTCP:LISTEN`, {
|
|
204
|
+
encoding: 'utf-8',
|
|
205
|
+
}).trim()
|
|
206
|
+
if (pid) {
|
|
207
|
+
console.info(`Killing process ${pid} on port ${METRO_PORT}...`)
|
|
208
|
+
process.kill(Number(pid), 'SIGTERM')
|
|
209
|
+
}
|
|
210
|
+
} catch {
|
|
211
|
+
// nothing listening, or lsof not available
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
170
215
|
/**
|
|
171
216
|
* Run a function with Metro bundler, ensuring proper cleanup.
|
|
172
217
|
* This is a convenience wrapper that handles starting Metro, waiting for it,
|
|
@@ -185,7 +230,9 @@ export async function withMetro<T>(platform: Platform, fn: () => Promise<T>): Pr
|
|
|
185
230
|
return await fn()
|
|
186
231
|
}
|
|
187
232
|
|
|
188
|
-
//
|
|
233
|
+
// kill anything on the port before starting (e.g. another project's Metro)
|
|
234
|
+
killPortProcess()
|
|
235
|
+
|
|
189
236
|
const metro = startMetro()
|
|
190
237
|
setupSignalHandlers(metro)
|
|
191
238
|
|
package/src/run-detox-android.ts
CHANGED
package/src/run-detox-ios.ts
CHANGED
package/types/detox.d.ts
CHANGED
|
@@ -17,6 +17,8 @@ export interface DetoxRunnerOptions {
|
|
|
17
17
|
headless?: boolean;
|
|
18
18
|
/** Number of parallel workers (default: 1) */
|
|
19
19
|
workers?: number;
|
|
20
|
+
/** Specific test files to run (passed as positional args to detox) */
|
|
21
|
+
testFiles?: string[];
|
|
20
22
|
}
|
|
21
23
|
/**
|
|
22
24
|
* Parse common CLI arguments for Detox runners
|
|
@@ -28,6 +30,7 @@ export declare function parseDetoxArgs(platform: Platform): {
|
|
|
28
30
|
recordLogs: string;
|
|
29
31
|
retries: number;
|
|
30
32
|
workers: number;
|
|
33
|
+
testFiles: string[] | undefined;
|
|
31
34
|
};
|
|
32
35
|
/**
|
|
33
36
|
* Build Detox CLI command arguments
|
package/types/detox.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"detox.d.ts","sourceRoot":"","sources":["../src/detox.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AAG3C,MAAM,WAAW,kBAAkB;IACjC,+BAA+B;IAC/B,MAAM,EAAE,MAAM,CAAA;IACd,6BAA6B;IAC7B,WAAW,EAAE,MAAM,CAAA;IACnB,2CAA2C;IAC3C,UAAU,EAAE,MAAM,CAAA;IAClB,wCAAwC;IACxC,OAAO,EAAE,MAAM,CAAA;IACf,0CAA0C;IAC1C,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,8CAA8C;IAC9C,OAAO,CAAC,EAAE,MAAM,CAAA;
|
|
1
|
+
{"version":3,"file":"detox.d.ts","sourceRoot":"","sources":["../src/detox.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AAG3C,MAAM,WAAW,kBAAkB;IACjC,+BAA+B;IAC/B,MAAM,EAAE,MAAM,CAAA;IACd,6BAA6B;IAC7B,WAAW,EAAE,MAAM,CAAA;IACnB,2CAA2C;IAC3C,UAAU,EAAE,MAAM,CAAA;IAClB,wCAAwC;IACxC,OAAO,EAAE,MAAM,CAAA;IACf,0CAA0C;IAC1C,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB,8CAA8C;IAC9C,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,sEAAsE;IACtE,SAAS,CAAC,EAAE,MAAM,EAAE,CAAA;CACrB;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,QAAQ;;;;;;;;EAsChD;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,kBAAkB,GAAG,MAAM,EAAE,CA6BpE;AAKD;;;GAGG;AACH,wBAAsB,kBAAkB,IAAI,OAAO,CAAC,IAAI,CAAC,CAOxD;AAED;;;;GAIG;AACH,wBAAsB,aAAa,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,MAAM,CAAC,CAwChF"}
|
package/types/ios.d.ts
CHANGED
|
@@ -1,6 +1,34 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* iOS-specific utilities for Detox test runners
|
|
3
3
|
*/
|
|
4
|
+
/**
|
|
5
|
+
* Check if any iOS simulator is booted and available for testing.
|
|
6
|
+
* Returns true if at least one simulator is booted.
|
|
7
|
+
*/
|
|
8
|
+
export declare function hasBootedSimulator(): boolean;
|
|
9
|
+
/**
|
|
10
|
+
* Get the UDID of the first booted iOS simulator, or null if none.
|
|
11
|
+
*/
|
|
12
|
+
export declare function getBootedSimulatorUDID(): string | null;
|
|
13
|
+
/**
|
|
14
|
+
* Boot an iOS simulator. Picks the first available iPhone device.
|
|
15
|
+
*/
|
|
16
|
+
export declare function ensureBootedSimulator(): void;
|
|
17
|
+
/**
|
|
18
|
+
* Ensure the app is installed on a specific simulator.
|
|
19
|
+
* For dev client apps, builds if needed then installs.
|
|
20
|
+
* For Expo Go apps, ensures Expo Go is present.
|
|
21
|
+
*/
|
|
22
|
+
export declare function ensureAppInstalled(opts: {
|
|
23
|
+
projectRoot: string;
|
|
24
|
+
bundleId: string;
|
|
25
|
+
udid?: string;
|
|
26
|
+
}): Promise<void>;
|
|
27
|
+
/**
|
|
28
|
+
* Get the bundle ID needed for maestro tests.
|
|
29
|
+
* Checks flow files first (they declare appId), falls back to app.json.
|
|
30
|
+
*/
|
|
31
|
+
export declare function getMaestroBundleId(projectRoot: string): string;
|
|
4
32
|
/**
|
|
5
33
|
* Shutdown all simulators and clean up zombie simulator processes.
|
|
6
34
|
* macOS doesn't properly clean up simulators between test runs, leading to
|
|
@@ -29,6 +57,7 @@ export declare function ensureIOSFolder(): Promise<void>;
|
|
|
29
57
|
*
|
|
30
58
|
* IMPORTANT: Fingerprint only changes when NATIVE dependencies change
|
|
31
59
|
* (Podfile, native modules, etc). JS-only changes don't require rebuild.
|
|
60
|
+
* Set SKIP_IOS_REBUILD=1 to skip rebuild even when fingerprint changes.
|
|
32
61
|
*/
|
|
33
62
|
export declare function ensureIOSApp(config?: string): Promise<void>;
|
|
34
63
|
//# sourceMappingURL=ios.d.ts.map
|
package/types/ios.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ios.d.ts","sourceRoot":"","sources":["../src/ios.ts"],"names":[],"mappings":"AAAA;;GAEG;AASH;;;;GAIG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC,CAoBvD;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC,CAgBrD;AAkCD
|
|
1
|
+
{"version":3,"file":"ios.d.ts","sourceRoot":"","sources":["../src/ios.ts"],"names":[],"mappings":"AAAA;;GAEG;AASH;;;GAGG;AACH,wBAAgB,kBAAkB,IAAI,OAAO,CAE5C;AAED;;GAEG;AACH,wBAAgB,sBAAsB,IAAI,MAAM,GAAG,IAAI,CAWtD;AAED;;GAEG;AACH,wBAAgB,qBAAqB,IAAI,IAAI,CAuB5C;AAgBD;;;;GAIG;AACH,wBAAsB,kBAAkB,CAAC,IAAI,EAAE;IAC7C,WAAW,EAAE,MAAM,CAAA;IACnB,QAAQ,EAAE,MAAM,CAAA;IAChB,IAAI,CAAC,EAAE,MAAM,CAAA;CACd,GAAG,OAAO,CAAC,IAAI,CAAC,CA+BhB;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAsB9D;AA+CD;;;;GAIG;AACH,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,IAAI,CAAC,CAoBvD;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC,CAgBrD;AAkCD;;;;;;;;;GASG;AACH,wBAAsB,YAAY,CAAC,MAAM,GAAE,MAAwB,GAAG,OAAO,CAAC,IAAI,CAAC,CAyElF"}
|
package/types/metro.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"metro.d.ts","sourceRoot":"","sources":["../src/metro.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,KAAK,CAAA;
|
|
1
|
+
{"version":3,"file":"metro.d.ts","sourceRoot":"","sources":["../src/metro.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,KAAK,CAAA;AAErC,OAAO,EAKL,KAAK,QAAQ,EAEd,MAAM,aAAa,CAAA;AAEpB,MAAM,WAAW,YAAY;IAC3B,wCAAwC;IACxC,QAAQ,EAAE,QAAQ,CAAA;IAClB,yCAAyC;IACzC,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,gDAAgD;IAChD,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB;AAED,MAAM,WAAW,YAAY;IAC3B,oCAAoC;IACpC,IAAI,EAAE,UAAU,CAAA;IAChB,8CAA8C;IAC9C,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;CAC1B;AAED;;;;GAIG;AACH,wBAAsB,YAAY,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,OAAO,CAAC,CA0B1E;AAED;;;GAGG;AACH,wBAAsB,aAAa,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAwBrE;AAsBD;;;;GAIG;AACH,wBAAgB,UAAU,IAAI,YAAY,CA2CzC;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,YAAY,GAAG,IAAI,CAS7D;AAkCD;;;;;;;GAOG;AACH,wBAAsB,SAAS,CAAC,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CA4BvF"}
|
package/dist/cache.js
DELETED
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
import { existsSync, readFileSync, writeFileSync, mkdirSync } from "node:fs";
|
|
2
|
-
import { dirname, join } from "node:path";
|
|
3
|
-
import { DEFAULT_KV_TTL_SECONDS } from "./constants";
|
|
4
|
-
function createCacheKey(options) {
|
|
5
|
-
const { platform, fingerprint, prefix = "native-build" } = options;
|
|
6
|
-
return `${prefix}-${platform}-${fingerprint}`;
|
|
7
|
-
}
|
|
8
|
-
async function saveFingerprintToKV(kv, key, fingerprint, ttlSeconds = DEFAULT_KV_TTL_SECONDS) {
|
|
9
|
-
try {
|
|
10
|
-
const response = await fetch(`${kv.url}/SETEX/${key}/${ttlSeconds}/${fingerprint}`, {
|
|
11
|
-
method: "POST",
|
|
12
|
-
headers: {
|
|
13
|
-
Authorization: `Bearer ${kv.token}`
|
|
14
|
-
}
|
|
15
|
-
});
|
|
16
|
-
if (!response.ok)
|
|
17
|
-
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
18
|
-
} catch (error) {
|
|
19
|
-
throw error instanceof TypeError ? new Error(`Network error connecting to KV store: ${error.message}`) : new Error(`Failed to save fingerprint to KV: ${error.message}`);
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
async function getFingerprintFromKV(kv, key) {
|
|
23
|
-
try {
|
|
24
|
-
const response = await fetch(`${kv.url}/get/${key}`, {
|
|
25
|
-
headers: {
|
|
26
|
-
Authorization: `Bearer ${kv.token}`
|
|
27
|
-
}
|
|
28
|
-
});
|
|
29
|
-
if (!response.ok)
|
|
30
|
-
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
31
|
-
const data = await response.json();
|
|
32
|
-
return data.result === "null" ? null : data.result;
|
|
33
|
-
} catch (error) {
|
|
34
|
-
throw error instanceof TypeError ? new Error(`Network error connecting to KV store: ${error.message}`) : new Error(`Failed to get fingerprint from KV: ${error.message}`);
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
async function extendKVTTL(kv, key, ttlSeconds = DEFAULT_KV_TTL_SECONDS) {
|
|
38
|
-
try {
|
|
39
|
-
await fetch(`${kv.url}/EXPIRE/${key}/${ttlSeconds}`, {
|
|
40
|
-
method: "POST",
|
|
41
|
-
headers: {
|
|
42
|
-
Authorization: `Bearer ${kv.token}`
|
|
43
|
-
}
|
|
44
|
-
});
|
|
45
|
-
} catch (error) {
|
|
46
|
-
console.warn(`Failed to extend KV TTL: ${error.message}`);
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
function saveCache(filePath, data, options = {}) {
|
|
50
|
-
const { cacheDir } = options, cachePath = cacheDir ? join(process.cwd(), cacheDir, filePath) : join(process.cwd(), filePath);
|
|
51
|
-
mkdirSync(dirname(cachePath), { recursive: !0 }), writeFileSync(cachePath, JSON.stringify(data, null, 2));
|
|
52
|
-
}
|
|
53
|
-
function loadCache(filePath, options = {}) {
|
|
54
|
-
const { cacheDir } = options, cachePath = cacheDir ? join(process.cwd(), cacheDir, filePath) : join(process.cwd(), filePath);
|
|
55
|
-
if (!existsSync(cachePath))
|
|
56
|
-
return null;
|
|
57
|
-
try {
|
|
58
|
-
return JSON.parse(readFileSync(cachePath, "utf-8"));
|
|
59
|
-
} catch {
|
|
60
|
-
return null;
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
export {
|
|
64
|
-
createCacheKey,
|
|
65
|
-
extendKVTTL,
|
|
66
|
-
getFingerprintFromKV,
|
|
67
|
-
loadCache,
|
|
68
|
-
saveCache,
|
|
69
|
-
saveFingerprintToKV
|
|
70
|
-
};
|
|
71
|
-
//# sourceMappingURL=cache.js.map
|
package/dist/cache.js.map
DELETED
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../src/cache.ts"],
|
|
4
|
-
"mappings": "AAAA,SAAS,YAAY,cAAc,eAAe,iBAAiB;AACnE,SAAS,SAAS,YAAY;AAC9B,SAAS,8BAA6C;AAgB/C,SAAS,eAAe,SAA+B;AAC5D,QAAM,EAAE,UAAU,aAAa,SAAS,eAAe,IAAI;AAC3D,SAAO,GAAG,MAAM,IAAI,QAAQ,IAAI,WAAW;AAC7C;AAMA,eAAsB,oBACpB,IACA,KACA,aACA,aAAa,wBACE;AACf,MAAI;AACF,UAAM,WAAW,MAAM,MAAM,GAAG,GAAG,GAAG,UAAU,GAAG,IAAI,UAAU,IAAI,WAAW,IAAI;AAAA,MAClF,QAAQ;AAAA,MACR,SAAS;AAAA,QACP,eAAe,UAAU,GAAG,KAAK;AAAA,MACnC;AAAA,IACF,CAAC;AAED,QAAI,CAAC,SAAS;AACZ,YAAM,IAAI,MAAM,QAAQ,SAAS,MAAM,KAAK,SAAS,UAAU,EAAE;AAAA,EAErE,SAAS,OAAO;AACd,UAAI,iBAAiB,YACb,IAAI,MAAM,yCAA0C,MAAgB,OAAO,EAAE,IAE/E,IAAI,MAAM,qCAAsC,MAAgB,OAAO,EAAE;AAAA,EACjF;AACF;AAKA,eAAsB,qBACpB,IACA,KACwB;AACxB,MAAI;AACF,UAAM,WAAW,MAAM,MAAM,GAAG,GAAG,GAAG,QAAQ,GAAG,IAAI;AAAA,MACnD,SAAS;AAAA,QACP,eAAe,UAAU,GAAG,KAAK;AAAA,MACnC;AAAA,IACF,CAAC;AAED,QAAI,CAAC,SAAS;AACZ,YAAM,IAAI,MAAM,QAAQ,SAAS,MAAM,KAAK,SAAS,UAAU,EAAE;AAGnE,UAAM,OAAQ,MAAM,SAAS,KAAK;AAClC,WAAO,KAAK,WAAW,SAAS,OAAO,KAAK;AAAA,EAC9C,SAAS,OAAO;AACd,UAAI,iBAAiB,YACb,IAAI,MAAM,yCAA0C,MAAgB,OAAO,EAAE,IAE/E,IAAI,MAAM,sCAAuC,MAAgB,OAAO,EAAE;AAAA,EAClF;AACF;AAKA,eAAsB,YACpB,IACA,KACA,aAAa,wBACE;AACf,MAAI;AACF,UAAM,MAAM,GAAG,GAAG,GAAG,WAAW,GAAG,IAAI,UAAU,IAAI;AAAA,MACnD,QAAQ;AAAA,MACR,SAAS;AAAA,QACP,eAAe,UAAU,GAAG,KAAK;AAAA,MACnC;AAAA,IACF,CAAC;AAAA,EACH,SAAS,OAAO;AAEd,YAAQ,KAAK,4BAA6B,MAAgB,OAAO,EAAE;AAAA,EACrE;AACF;AAYO,SAAS,UACd,UACA,MACA,UAA6B,CAAC,GACxB;AACN,QAAM,EAAE,SAAS,IAAI,SACf,YAAY,WACd,KAAK,QAAQ,IAAI,GAAG,UAAU,QAAQ,IACtC,KAAK,QAAQ,IAAI,GAAG,QAAQ;AAEhC,YAAU,QAAQ,SAAS,GAAG,EAAE,WAAW,GAAK,CAAC,GACjD,cAAc,WAAW,KAAK,UAAU,MAAM,MAAM,CAAC,CAAC;AACxD;AAMO,SAAS,UACd,UACA,UAA6B,CAAC,GACpB;AACV,QAAM,EAAE,SAAS,IAAI,SACf,YAAY,WACd,KAAK,QAAQ,IAAI,GAAG,UAAU,QAAQ,IACtC,KAAK,QAAQ,IAAI,GAAG,QAAQ;AAEhC,MAAI,CAAC,WAAW,SAAS;AACvB,WAAO;AAGT,MAAI;AACF,WAAO,KAAK,MAAM,aAAa,WAAW,OAAO,CAAC;AAAA,EACpD,QAAQ;AACN,WAAO;AAAA,EACT;AACF;",
|
|
5
|
-
"names": []
|
|
6
|
-
}
|