@e2e-dev/eas 0.1.1 → 0.2.1
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/README.md +7 -3
- package/dist/.build.json +1 -1
- package/dist/client.d.ts +3 -3
- package/dist/client.js +4 -4
- package/dist/credentials.d.ts +19 -0
- package/dist/credentials.js +46 -0
- package/dist/env.d.ts +0 -1
- package/dist/env.js +0 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.js +0 -1
- package/dist/project.d.ts +12 -0
- package/dist/project.js +99 -0
- package/dist/provider.d.ts +12 -6
- package/dist/provider.js +49 -16
- package/package.json +3 -3
- package/dist/client.d.ts.map +0 -1
- package/dist/client.js.map +0 -1
- package/dist/env.d.ts.map +0 -1
- package/dist/env.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/provider.d.ts.map +0 -1
- package/dist/provider.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# @e2e-dev/eas
|
|
2
2
|
|
|
3
3
|
[EAS Simulators](https://expo.dev/services/simulators) for [`e2e`](https://www.npmjs.com/package/e2e):
|
|
4
|
-
`mobile({ device: easSimulators(
|
|
4
|
+
`mobile({ device: easSimulators() })` runs a mobile target on
|
|
5
5
|
Expo's hosted iOS simulators and Android emulators.
|
|
6
6
|
|
|
7
7
|
## Install
|
|
@@ -22,7 +22,7 @@ export default {
|
|
|
22
22
|
{
|
|
23
23
|
engine: mobile({
|
|
24
24
|
platform: 'ios',
|
|
25
|
-
device: easSimulators({
|
|
25
|
+
device: easSimulators({ buildId: process.env.EAS_BUILD_ID }),
|
|
26
26
|
videoTouches: false,
|
|
27
27
|
}),
|
|
28
28
|
app: { bundleId: 'com.example.app' },
|
|
@@ -32,7 +32,11 @@ export default {
|
|
|
32
32
|
} satisfies E2EConfig;
|
|
33
33
|
```
|
|
34
34
|
|
|
35
|
-
|
|
35
|
+
The sessions belong to the Expo project the app config beside
|
|
36
|
+
`e2e.config.ts` links (`extra.eas.projectId`, from `app.json` or as
|
|
37
|
+
`expo config` evaluates `app.config.ts`); `projectId` names another.
|
|
38
|
+
It authenticates with `EXPO_TOKEN` from the run's environment, else with the
|
|
39
|
+
session `eas login` stored, as eas-cli does. Each worker slot gets its own
|
|
36
40
|
EAS Simulators session, started when the run starts and stopped when it ends,
|
|
37
41
|
and the engine drives it through the agent-device daemon EAS runs beside it.
|
|
38
42
|
Tests start once every slot has a simulator.
|
package/dist/.build.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":"0.
|
|
1
|
+
{"version":"0.2.1"}
|
package/dist/client.d.ts
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* EAS Simulators' sessions through Expo's GraphQL API over `fetch`, the API
|
|
3
3
|
* `eas simulator:*` uses, so the integration installs no SDK.
|
|
4
4
|
*/
|
|
5
|
+
import type { ExpoCredentials } from './credentials.ts';
|
|
5
6
|
/** What the provider asks EAS for: one agent-device session on one platform. */
|
|
6
7
|
export interface EasSessionParams {
|
|
7
8
|
readonly appId: string;
|
|
@@ -46,6 +47,5 @@ export interface EasSessions {
|
|
|
46
47
|
*/
|
|
47
48
|
stop(id: string, signal: AbortSignal): Promise<void>;
|
|
48
49
|
}
|
|
49
|
-
/** EAS Simulators sessions for one Expo access token. */
|
|
50
|
-
export declare function easSessions(
|
|
51
|
-
//# sourceMappingURL=client.d.ts.map
|
|
50
|
+
/** EAS Simulators sessions for one Expo access token or eas-cli session. */
|
|
51
|
+
export declare function easSessions(credentials: ExpoCredentials): EasSessions;
|
package/dist/client.js
CHANGED
|
@@ -23,13 +23,14 @@ const CANCEL_JOB = `mutation ($id: ID!) {
|
|
|
23
23
|
const QUEUED_JOB = new Set(['NEW', 'IN_QUEUE']);
|
|
24
24
|
/** Job run states after which the session never becomes ready. */
|
|
25
25
|
const ENDED_JOB = new Set(['ERRORED', 'CANCELED', 'FINISHED', 'PENDING_CANCEL']);
|
|
26
|
-
/** EAS Simulators sessions for one Expo access token. */
|
|
27
|
-
export function easSessions(
|
|
26
|
+
/** EAS Simulators sessions for one Expo access token or eas-cli session. */
|
|
27
|
+
export function easSessions(credentials) {
|
|
28
|
+
const auth = 'accessToken' in credentials ? { Authorization: `Bearer ${credentials.accessToken}` } : { 'expo-session': credentials.sessionSecret };
|
|
28
29
|
/** Runs one operation; a GraphQL error throws with EAS's message and error code. */
|
|
29
30
|
const graphql = async (query, variables, signal) => {
|
|
30
31
|
const response = await fetch(GRAPHQL_URL, {
|
|
31
32
|
method: 'POST',
|
|
32
|
-
headers: {
|
|
33
|
+
headers: { ...auth, 'Content-Type': 'application/json' },
|
|
33
34
|
body: JSON.stringify({ query, variables }),
|
|
34
35
|
signal,
|
|
35
36
|
});
|
|
@@ -100,4 +101,3 @@ class EasError extends Error {
|
|
|
100
101
|
this.code = code;
|
|
101
102
|
}
|
|
102
103
|
}
|
|
103
|
-
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Expo credentials a run authenticates with, in eas-cli's order:
|
|
3
|
+
* `EXPO_TOKEN` when it is set, else the session `eas login` stored, so a
|
|
4
|
+
* machine signed in to eas-cli needs no token. Only the production login is
|
|
5
|
+
* read: the sessions API is always `api.expo.dev`, and eas-cli's staging and
|
|
6
|
+
* local logins belong to other hosts.
|
|
7
|
+
*/
|
|
8
|
+
export declare const EXPO_TOKEN = "EXPO_TOKEN";
|
|
9
|
+
/** An access token goes out as `Authorization: Bearer`, an eas-cli session secret as `expo-session`. */
|
|
10
|
+
export type ExpoCredentials = {
|
|
11
|
+
readonly accessToken: string;
|
|
12
|
+
} | {
|
|
13
|
+
readonly sessionSecret: string;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* `EXPO_TOKEN` from the run's environment, else the `auth.sessionSecret` eas-cli
|
|
17
|
+
* keeps in `state.json`; `undefined` when there is neither.
|
|
18
|
+
*/
|
|
19
|
+
export declare function expoCredentials(env: Readonly<Record<string, string | undefined>>): Promise<ExpoCredentials | undefined>;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Expo credentials a run authenticates with, in eas-cli's order:
|
|
3
|
+
* `EXPO_TOKEN` when it is set, else the session `eas login` stored, so a
|
|
4
|
+
* machine signed in to eas-cli needs no token. Only the production login is
|
|
5
|
+
* read: the sessions API is always `api.expo.dev`, and eas-cli's staging and
|
|
6
|
+
* local logins belong to other hosts.
|
|
7
|
+
*/
|
|
8
|
+
import { readFile } from 'node:fs/promises';
|
|
9
|
+
import { homedir } from 'node:os';
|
|
10
|
+
import { join } from 'node:path';
|
|
11
|
+
import { envValue } from './env.js';
|
|
12
|
+
export const EXPO_TOKEN = 'EXPO_TOKEN';
|
|
13
|
+
/**
|
|
14
|
+
* `EXPO_TOKEN` from the run's environment, else the `auth.sessionSecret` eas-cli
|
|
15
|
+
* keeps in `state.json`; `undefined` when there is neither.
|
|
16
|
+
*/
|
|
17
|
+
export async function expoCredentials(env) {
|
|
18
|
+
const accessToken = envValue(env, EXPO_TOKEN);
|
|
19
|
+
if (accessToken !== undefined)
|
|
20
|
+
return { accessToken };
|
|
21
|
+
const path = stateJsonPath(env);
|
|
22
|
+
let text;
|
|
23
|
+
try {
|
|
24
|
+
text = await readFile(path, 'utf8');
|
|
25
|
+
}
|
|
26
|
+
catch (cause) {
|
|
27
|
+
if (cause.code === 'ENOENT')
|
|
28
|
+
return undefined;
|
|
29
|
+
throw new Error(`could not read the eas-cli login at ${path}: ${cause instanceof Error ? cause.message : String(cause)}`, { cause });
|
|
30
|
+
}
|
|
31
|
+
let state;
|
|
32
|
+
try {
|
|
33
|
+
state = JSON.parse(text);
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
// No cause: a JSON parse error quotes the text around the fault, which can be the secret.
|
|
37
|
+
throw new Error(`the eas-cli login at ${path} is not valid JSON; run \`eas login\` again, or set ${EXPO_TOKEN}`);
|
|
38
|
+
}
|
|
39
|
+
const sessionSecret = state?.auth?.sessionSecret;
|
|
40
|
+
return typeof sessionSecret === 'string' && sessionSecret.trim() !== '' ? { sessionSecret: sessionSecret.trim() } : undefined;
|
|
41
|
+
}
|
|
42
|
+
/** eas-cli's production `state.json` under the run's home: `USERPROFILE` on Windows and `HOME` elsewhere, as `os.homedir()` resolves it. */
|
|
43
|
+
function stateJsonPath(env) {
|
|
44
|
+
const home = envValue(env, process.platform === 'win32' ? 'USERPROFILE' : 'HOME') ?? homedir();
|
|
45
|
+
return join(home, '.expo', 'state.json');
|
|
46
|
+
}
|
package/dist/env.d.ts
CHANGED
package/dist/env.js
CHANGED
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Expo project id a run's sessions belong to when `easSimulators()` names
|
|
3
|
+
* none: `extra.eas.projectId` of the app config in the e2e project root, the
|
|
4
|
+
* id `eas init` writes.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* `extra.eas.projectId` from the app config in `projectRoot`. A dynamic
|
|
8
|
+
* config (`app.config.ts` and its siblings) is evaluated by the project's
|
|
9
|
+
* own `expo config`, with the run's environment, since it can compute the
|
|
10
|
+
* id; a static one (`app.config.json`, `app.json`) is read as JSON.
|
|
11
|
+
*/
|
|
12
|
+
export declare function appConfigProjectId(projectRoot: string, env: Readonly<Record<string, string | undefined>>, signal: AbortSignal): Promise<string>;
|
package/dist/project.js
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Expo project id a run's sessions belong to when `easSimulators()` names
|
|
3
|
+
* none: `extra.eas.projectId` of the app config in the e2e project root, the
|
|
4
|
+
* id `eas init` writes.
|
|
5
|
+
*/
|
|
6
|
+
import { execFile } from 'node:child_process';
|
|
7
|
+
import { existsSync } from 'node:fs';
|
|
8
|
+
import { readFile } from 'node:fs/promises';
|
|
9
|
+
import { dirname, join } from 'node:path';
|
|
10
|
+
import { promisify } from 'node:util';
|
|
11
|
+
const execFileAsync = promisify(execFile);
|
|
12
|
+
/** The dynamic app config names Expo resolves, in its order; one of them wins over `app.json`. */
|
|
13
|
+
const DYNAMIC_CONFIGS = ['app.config.ts', 'app.config.mts', 'app.config.cts', 'app.config.mjs', 'app.config.cjs', 'app.config.js'];
|
|
14
|
+
/** The static app config names Expo resolves, in its order. */
|
|
15
|
+
const STATIC_CONFIGS = ['app.config.json', 'app.json'];
|
|
16
|
+
/** How long `expo config` may evaluate a dynamic config; it takes about a second. */
|
|
17
|
+
const EXPO_CONFIG_TIMEOUT_MS = 60_000;
|
|
18
|
+
const PASS_IT = 'pass `projectId` to easSimulators(), or run `eas init` to link the app to an EAS project';
|
|
19
|
+
/**
|
|
20
|
+
* `extra.eas.projectId` from the app config in `projectRoot`. A dynamic
|
|
21
|
+
* config (`app.config.ts` and its siblings) is evaluated by the project's
|
|
22
|
+
* own `expo config`, with the run's environment, since it can compute the
|
|
23
|
+
* id; a static one (`app.config.json`, `app.json`) is read as JSON.
|
|
24
|
+
*/
|
|
25
|
+
export async function appConfigProjectId(projectRoot, env, signal) {
|
|
26
|
+
const dynamic = DYNAMIC_CONFIGS.find((name) => existsSync(join(projectRoot, name)));
|
|
27
|
+
if (dynamic !== undefined)
|
|
28
|
+
return projectIdOf(await evaluatedConfig(projectRoot, env, signal), `${dynamic} (through \`expo config\`)`);
|
|
29
|
+
const fixed = STATIC_CONFIGS.find((name) => existsSync(join(projectRoot, name)));
|
|
30
|
+
if (fixed === undefined)
|
|
31
|
+
throw new Error(`no Expo app config (app.json or app.config.*) in ${projectRoot}; ${PASS_IT}`);
|
|
32
|
+
const path = join(projectRoot, fixed);
|
|
33
|
+
let config;
|
|
34
|
+
try {
|
|
35
|
+
config = JSON.parse(await readFile(path, { encoding: 'utf8', signal }));
|
|
36
|
+
}
|
|
37
|
+
catch (cause) {
|
|
38
|
+
throw new Error(`could not read the Expo app config at ${path}: ${cause instanceof Error ? cause.message : String(cause)}`, { cause });
|
|
39
|
+
}
|
|
40
|
+
// Expo reads the app config from under `expo` when the file has that key, else the whole file.
|
|
41
|
+
const expo = isRecord(config) && isRecord(config['expo']) ? config['expo'] : config;
|
|
42
|
+
return projectIdOf(expo, fixed);
|
|
43
|
+
}
|
|
44
|
+
/** The public app config `expo config` prints for `projectRoot`, run with the project's own `expo` package. */
|
|
45
|
+
async function evaluatedConfig(projectRoot, env, signal) {
|
|
46
|
+
const cli = expoCli(projectRoot);
|
|
47
|
+
if (cli === undefined) {
|
|
48
|
+
throw new Error(`the app config in ${projectRoot} is dynamic and \`expo\` is not installed there to evaluate it; install it, or ${PASS_IT}`);
|
|
49
|
+
}
|
|
50
|
+
let stdout;
|
|
51
|
+
try {
|
|
52
|
+
({ stdout } = await execFileAsync(process.execPath, [cli, 'config', '--json', '--type', 'public'], {
|
|
53
|
+
cwd: projectRoot,
|
|
54
|
+
// As eas-cli runs it: the id comes from the config and the run's environment, never from a `.env` file.
|
|
55
|
+
env: { ...env, EXPO_NO_DOTENV: '1' },
|
|
56
|
+
signal,
|
|
57
|
+
timeout: EXPO_CONFIG_TIMEOUT_MS,
|
|
58
|
+
maxBuffer: 16 * 1024 * 1024,
|
|
59
|
+
}));
|
|
60
|
+
}
|
|
61
|
+
catch (cause) {
|
|
62
|
+
const stderr = cause.stderr;
|
|
63
|
+
const detail = typeof stderr === 'string' && stderr.trim() !== '' ? stderr.trim() : cause instanceof Error ? cause.message : String(cause);
|
|
64
|
+
throw new Error(`\`expo config\` failed in ${projectRoot}: ${detail}`, { cause });
|
|
65
|
+
}
|
|
66
|
+
try {
|
|
67
|
+
return JSON.parse(stdout);
|
|
68
|
+
}
|
|
69
|
+
catch (cause) {
|
|
70
|
+
throw new Error(`\`expo config\` in ${projectRoot} printed no JSON config`, { cause });
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* The `expo` CLI in the `node_modules` of `projectRoot` or a parent, as Expo
|
|
75
|
+
* resolves it: never through `NODE_PATH` or Node's global folders, which
|
|
76
|
+
* pnpm points at its whole store and which hold some other project's `expo`.
|
|
77
|
+
*/
|
|
78
|
+
function expoCli(projectRoot) {
|
|
79
|
+
for (let directory = projectRoot;; directory = dirname(directory)) {
|
|
80
|
+
const cli = join(directory, 'node_modules', 'expo', 'bin', 'cli');
|
|
81
|
+
if (existsSync(cli))
|
|
82
|
+
return cli;
|
|
83
|
+
if (dirname(directory) === directory)
|
|
84
|
+
return undefined;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
/** `extra.eas.projectId` of an app config, named after the file it came from when it is missing. */
|
|
88
|
+
function projectIdOf(config, source) {
|
|
89
|
+
const extra = isRecord(config) ? config['extra'] : undefined;
|
|
90
|
+
const eas = isRecord(extra) ? extra['eas'] : undefined;
|
|
91
|
+
const projectId = isRecord(eas) ? eas['projectId'] : undefined;
|
|
92
|
+
if (typeof projectId === 'string' && projectId.trim() !== '')
|
|
93
|
+
return projectId.trim();
|
|
94
|
+
throw new Error(`${source} has no \`extra.eas.projectId\`; ${PASS_IT}`);
|
|
95
|
+
}
|
|
96
|
+
/** A plain JSON object, not an array or `null`. */
|
|
97
|
+
function isRecord(value) {
|
|
98
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
99
|
+
}
|
package/dist/provider.d.ts
CHANGED
|
@@ -2,8 +2,13 @@
|
|
|
2
2
|
import type { DeviceProvider } from '@e2e-dev/mobile';
|
|
3
3
|
/** What `easSimulators()` takes: the Expo project, the app each simulator starts with, and the simulator itself. */
|
|
4
4
|
export interface EasSimulatorsOptions {
|
|
5
|
-
/**
|
|
6
|
-
|
|
5
|
+
/**
|
|
6
|
+
* The Expo project the sessions belong to: its id, not its slug. Absent,
|
|
7
|
+
* `extra.eas.projectId` of the app config in the project root, the id
|
|
8
|
+
* `eas init` writes: `app.json` or `app.config.json` as written, a dynamic
|
|
9
|
+
* `app.config.ts` or `.js` as the project's `expo config` evaluates it.
|
|
10
|
+
*/
|
|
11
|
+
readonly projectId?: string | undefined;
|
|
7
12
|
/**
|
|
8
13
|
* EAS Build EAS installs and launches on every simulator before the session
|
|
9
14
|
* is ready: a simulator build (`ios.simulator: true`) or an APK. Pair it
|
|
@@ -37,8 +42,9 @@ export interface EasSimulatorsOptions {
|
|
|
37
42
|
* EAS Simulators for `mobile({ device: easSimulators() })`: one hosted
|
|
38
43
|
* simulator per worker slot, started when the run starts and stopped when it
|
|
39
44
|
* ends, each driven through the agent-device daemon EAS runs beside it.
|
|
40
|
-
* Every session is named after its target and slot and tagged with the run
|
|
41
|
-
* `
|
|
45
|
+
* Every session is named after its target and slot and tagged with the run,
|
|
46
|
+
* in the project `projectId` names or the app config links.
|
|
47
|
+
* It authenticates with `EXPO_TOKEN` from the run's environment, else with
|
|
48
|
+
* the session `eas login` stored, as eas-cli does.
|
|
42
49
|
*/
|
|
43
|
-
export declare function easSimulators(options
|
|
44
|
-
//# sourceMappingURL=provider.d.ts.map
|
|
50
|
+
export declare function easSimulators(options?: EasSimulatorsOptions): DeviceProvider;
|
package/dist/provider.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/** EAS Simulators' hosted iOS simulators and Android emulators as a `DeviceProvider` for the mobile engine. */
|
|
2
2
|
import { setTimeout as sleep } from 'node:timers/promises';
|
|
3
3
|
import { ConfigurationError, rejectUnknownKeys } from 'e2e/engine';
|
|
4
|
-
import { envValue } from './env.js';
|
|
5
4
|
import { easSessions } from './client.js';
|
|
6
|
-
|
|
5
|
+
import { EXPO_TOKEN, expoCredentials } from './credentials.js';
|
|
6
|
+
import { appConfigProjectId } from './project.js';
|
|
7
7
|
/**
|
|
8
8
|
* EAS stops a session no agent-device command reached for this long: the
|
|
9
9
|
* backstop for a run that died before the engine could release its lease.
|
|
@@ -24,6 +24,12 @@ const POLL_FAILURES_TOLERATED = 3;
|
|
|
24
24
|
* while the next target's queue.
|
|
25
25
|
*/
|
|
26
26
|
const idleDeadlines = new Map();
|
|
27
|
+
/**
|
|
28
|
+
* The project id each run reads from an app config, by run and project root,
|
|
29
|
+
* across every `easSimulators()` of the run, so two targets of one app read it
|
|
30
|
+
* once. A failed read is not kept.
|
|
31
|
+
*/
|
|
32
|
+
const projectIds = new Map();
|
|
27
33
|
/** Every option `easSimulators()` takes, kept equal to `EasSimulatorsOptions` by the compiler. */
|
|
28
34
|
const OPTION_KEYS = Object.keys({
|
|
29
35
|
projectId: true,
|
|
@@ -39,10 +45,12 @@ const OPTION_KEYS = Object.keys({
|
|
|
39
45
|
* EAS Simulators for `mobile({ device: easSimulators() })`: one hosted
|
|
40
46
|
* simulator per worker slot, started when the run starts and stopped when it
|
|
41
47
|
* ends, each driven through the agent-device daemon EAS runs beside it.
|
|
42
|
-
* Every session is named after its target and slot and tagged with the run
|
|
43
|
-
* `
|
|
48
|
+
* Every session is named after its target and slot and tagged with the run,
|
|
49
|
+
* in the project `projectId` names or the app config links.
|
|
50
|
+
* It authenticates with `EXPO_TOKEN` from the run's environment, else with
|
|
51
|
+
* the session `eas login` stored, as eas-cli does.
|
|
44
52
|
*/
|
|
45
|
-
export function easSimulators(options) {
|
|
53
|
+
export function easSimulators(options = {}) {
|
|
46
54
|
rejectUnknownKeys('easSimulators()', options, OPTION_KEYS);
|
|
47
55
|
const { projectId, buildId, applicationArchiveUrl, device, maxDurationMinutes, agentDeviceVersion, tags = [] } = options;
|
|
48
56
|
if (buildId !== undefined && applicationArchiveUrl !== undefined) {
|
|
@@ -54,15 +62,34 @@ export function easSimulators(options) {
|
|
|
54
62
|
const idleMinutes = options.maxIdleTimeMinutes ?? (maxDurationMinutes === undefined ? DEFAULT_MAX_IDLE_TIME_MINUTES : Math.min(DEFAULT_MAX_IDLE_TIME_MINUTES, maxDurationMinutes - 1));
|
|
55
63
|
// EAS takes no idle limit of zero; a session that short runs to its duration.
|
|
56
64
|
const maxIdleTimeMinutes = idleMinutes >= 1 ? idleMinutes : undefined;
|
|
65
|
+
const projectIdFor = (request) => {
|
|
66
|
+
if (projectId !== undefined)
|
|
67
|
+
return Promise.resolve(projectId);
|
|
68
|
+
// The peer range admits an @e2e-dev/mobile from before providers were told the project root.
|
|
69
|
+
if (typeof request.projectRoot !== 'string') {
|
|
70
|
+
return Promise.reject(new Error('reading `projectId` from the app config needs an @e2e-dev/mobile that passes `projectRoot` to device providers; upgrade it, or pass `projectId`'));
|
|
71
|
+
}
|
|
72
|
+
const key = `${request.runId}\0${request.projectRoot}`;
|
|
73
|
+
let resolved = projectIds.get(key);
|
|
74
|
+
if (resolved === undefined) {
|
|
75
|
+
resolved = appConfigProjectId(request.projectRoot, request.env, request.signal);
|
|
76
|
+
projectIds.set(key, resolved);
|
|
77
|
+
resolved.catch(() => projectIds.delete(key));
|
|
78
|
+
}
|
|
79
|
+
return resolved;
|
|
80
|
+
};
|
|
57
81
|
const clients = new Map();
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
82
|
+
/** The client each lease was created with, so `release` stops it as the same account even if the eas-cli login changed during the run. */
|
|
83
|
+
const leaseClients = new Map();
|
|
84
|
+
const clientFor = async (env) => {
|
|
85
|
+
const credentials = await expoCredentials(env);
|
|
86
|
+
if (credentials === undefined)
|
|
87
|
+
throw new Error(`${EXPO_TOKEN} is not set and eas-cli is not logged in; run \`eas login\` or set ${EXPO_TOKEN}`);
|
|
88
|
+
const key = 'accessToken' in credentials ? `token:${credentials.accessToken}` : `session:${credentials.sessionSecret}`;
|
|
89
|
+
let client = clients.get(key);
|
|
63
90
|
if (client === undefined) {
|
|
64
|
-
client = easSessions(
|
|
65
|
-
clients.set(
|
|
91
|
+
client = easSessions(credentials);
|
|
92
|
+
clients.set(key, client);
|
|
66
93
|
}
|
|
67
94
|
return client;
|
|
68
95
|
};
|
|
@@ -72,10 +99,11 @@ export function easSimulators(options) {
|
|
|
72
99
|
if (request.appPath !== undefined && (buildId !== undefined || applicationArchiveUrl !== undefined)) {
|
|
73
100
|
throw new Error("EAS installs the app from `buildId` or `applicationArchiveUrl`; leave the target's `app.appPath` out");
|
|
74
101
|
}
|
|
75
|
-
const
|
|
102
|
+
const appId = await projectIdFor(request);
|
|
103
|
+
const client = await clientFor(request.env);
|
|
76
104
|
// Not the request's signal: an interrupt that lands after EAS created the session would leave it unknown, and billed.
|
|
77
105
|
const created = await client.create({
|
|
78
|
-
appId
|
|
106
|
+
appId,
|
|
79
107
|
platform: request.platform,
|
|
80
108
|
name: `e2e ${request.targetName} ${request.slot + 1} of ${request.slots}`,
|
|
81
109
|
tags: [...tags, 'e2e', `e2e-run:${request.runId}`, `e2e-target:${request.targetName}`],
|
|
@@ -99,6 +127,7 @@ export function easSimulators(options) {
|
|
|
99
127
|
}
|
|
100
128
|
held.set(created.id, Date.now() + maxIdleTimeMinutes * 60_000);
|
|
101
129
|
}
|
|
130
|
+
leaseClients.set(created.id, client);
|
|
102
131
|
return { id: created.id, daemon: { baseUrl: session.daemonUrl, authToken: session.daemonToken } };
|
|
103
132
|
}
|
|
104
133
|
catch (cause) {
|
|
@@ -109,11 +138,16 @@ export function easSimulators(options) {
|
|
|
109
138
|
}
|
|
110
139
|
},
|
|
111
140
|
async release(lease, context) {
|
|
141
|
+
for (const key of projectIds.keys())
|
|
142
|
+
if (key.startsWith(`${context.runId}\0`))
|
|
143
|
+
projectIds.delete(key);
|
|
112
144
|
const held = idleDeadlines.get(context.runId);
|
|
113
145
|
held?.delete(lease.id);
|
|
114
146
|
if (held?.size === 0)
|
|
115
147
|
idleDeadlines.delete(context.runId);
|
|
116
|
-
|
|
148
|
+
const client = leaseClients.get(lease.id) ?? (await clientFor(context.env));
|
|
149
|
+
await client.stop(lease.id, context.signal);
|
|
150
|
+
leaseClients.delete(lease.id);
|
|
117
151
|
},
|
|
118
152
|
};
|
|
119
153
|
}
|
|
@@ -165,4 +199,3 @@ async function ready(client, id, request) {
|
|
|
165
199
|
await sleep(POLL_INTERVAL_MS, undefined, { signal: request.signal });
|
|
166
200
|
}
|
|
167
201
|
}
|
|
168
|
-
//# sourceMappingURL=provider.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@e2e-dev/eas",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "EAS Simulators for e2e: run mobile targets on Expo's hosted iOS simulators and Android emulators",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"e2e",
|
|
@@ -49,9 +49,9 @@
|
|
|
49
49
|
"e2e": ">=0.15.0 <1"
|
|
50
50
|
},
|
|
51
51
|
"devDependencies": {
|
|
52
|
-
"@e2e-dev/mobile": "0.
|
|
52
|
+
"@e2e-dev/mobile": "0.9.1",
|
|
53
53
|
"@types/node": "26.6.2",
|
|
54
|
-
"e2e": "0.
|
|
54
|
+
"e2e": "0.16.0",
|
|
55
55
|
"typescript": "7.0.2",
|
|
56
56
|
"vitest": "5.0.1"
|
|
57
57
|
},
|
package/dist/client.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,gFAAgF;AAChF,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,QAAQ,EAAE,KAAK,GAAG,SAAS,CAAC;IACrC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACtC,QAAQ,CAAC,qBAAqB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACpD,sEAAsE;IACtE,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/C,QAAQ,CAAC,kBAAkB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACjD,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAChD,yDAAyD;IACzD,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC9C;AAED,4IAA4I;AAC5I,MAAM,MAAM,eAAe,GACvB;IAAE,QAAQ,CAAC,KAAK,EAAE,QAAQ,GAAG,UAAU,CAAA;CAAE,GACzC;IACE,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,kHAAkH;IAClH,QAAQ,CAAC,cAAc,EAAE,MAAM,GAAG,SAAS,CAAC;CAC7C,GACD;IAAE,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAEzD,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,sCAAsC;IACtC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,CAAC,MAAM,EAAE,gBAAgB,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAC;IAClF,KAAK,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC;IACjE;;;;;OAKG;IACH,IAAI,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACtD;AA2CD,yDAAyD;AACzD,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,WAAW,CA2DtD"}
|
package/dist/client.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
package/dist/env.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"env.d.ts","sourceRoot":"","sources":["../src/env.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,wBAAgB,QAAQ,CAAC,GAAG,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAG5G"}
|
package/dist/env.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"env.js","sourceRoot":"","sources":["../src/env.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,MAAM,UAAU,QAAQ,CAAC,GAAiD,EAAE,IAAY;IACtF,MAAM,KAAK,GAAG,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC;IAChC,OAAO,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC;AACjE,CAAC"}
|
package/dist/index.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAC9C,YAAY,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC"}
|
package/dist/index.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC"}
|
package/dist/provider.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../src/provider.ts"],"names":[],"mappings":"AAAA,+GAA+G;AAG/G,OAAO,KAAK,EAAe,cAAc,EAAuC,MAAM,iBAAiB,CAAC;AA6CxG,oHAAoH;AACpH,MAAM,WAAW,oBAAoB;IACnC,+GAA+G;IAC/G,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B;;;;OAIG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACtC,qGAAqG;IACrG,QAAQ,CAAC,qBAAqB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACpD,2IAA2I;IAC3I,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACrC;;;;;;OAMG;IACH,QAAQ,CAAC,kBAAkB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACjD,+HAA+H;IAC/H,QAAQ,CAAC,kBAAkB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACjD;;;;OAIG;IACH,QAAQ,CAAC,kBAAkB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACjD,+EAA+E;IAC/E,QAAQ,CAAC,IAAI,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,CAAC;CAC/C;AAED;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,oBAAoB,GAAG,cAAc,CA4E3E"}
|
package/dist/provider.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"provider.js","sourceRoot":"","sources":["../src/provider.ts"],"names":[],"mappings":"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"}
|