Skip to content

Commit

Permalink
feat: new global lifecycle for Detox (#3333)
Browse files Browse the repository at this point in the history
  • Loading branch information
noomorph committed Sep 5, 2022
1 parent 03d08d7 commit 6ff7c41
Show file tree
Hide file tree
Showing 242 changed files with 6,227 additions and 4,595 deletions.
4 changes: 3 additions & 1 deletion detox/__tests__/setupJest.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
jest.mock('proper-lockfile');
jest.mock('signal-exit');
jest.mock('../src/logger/DetoxLogger');

const path = require('path');

Expand Down Expand Up @@ -36,5 +38,5 @@ function callCli(modulePath, cmd) {
});
}

// @ts-ignore
global.callCli = callCli;
global.IS_RUNNING_DETOX_UNIT_TESTS = true;
219 changes: 161 additions & 58 deletions detox/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
// * Max Komarychev <https://github.com/maxkomarychev>
// * Dor Ben Baruch <https://github.com/Dor256>

import { BunyanDebugStreamOptions } from 'bunyan-debug-stream';

declare global {
const device: Detox.DetoxExportWrapper['device'];
const element: Detox.DetoxExportWrapper['element'];
Expand Down Expand Up @@ -36,21 +38,7 @@ declare global {
* @example extends: '@my-org/detox-preset'
*/
extends?: string;
/**
* Override test runner binary command.
* @default 'jest'
*/
testRunner?: string;
/**
* @example runnerConfig: 'e2e/config.js'
*/
runnerConfig?: string;
/**
* Optional. A default glob pattern for a test runner to use when no test files are specified.
*
* @example specs: 'detoxE2E'
*/
specs?: string;

apps?: Record<string, DetoxAppConfig>;
devices?: Record<string, DetoxDeviceConfig>;
selectedConfiguration?: string;
Expand All @@ -60,7 +48,9 @@ declare global {
type DetoxConfigurationCommon = {
artifacts?: false | DetoxArtifactsConfig;
behavior?: DetoxBehaviorConfig;
logger?: DetoxLoggerConfig;
session?: DetoxSessionConfig;
testRunner?: DetoxTestRunnerConfig;
};

interface DetoxArtifactsConfig {
Expand All @@ -71,7 +61,6 @@ declare global {
screenshot?: 'none' | 'manual' | 'failing' | 'all' | DetoxScreenshotArtifactsPluginConfig;
video?: 'none' | 'failing' | 'all' | DetoxVideoArtifactsPluginConfig;
instruments?: 'none' | 'all' | DetoxInstrumentsArtifactsPluginConfig;
timeline?: 'none' | 'all' | DetoxTimelineArtifactsPluginConfig;
uiHierarchy?: 'disabled' | 'enabled' | DetoxUIHierarchyArtifactsPluginConfig;

[pluginId: string]: unknown;
Expand All @@ -91,25 +80,85 @@ declare global {
*/
exposeGlobals?: boolean;
/**
* By default, `await detox.init()` will uninstall and install the app.
* By default, Detox will uninstall and install the app upon the initialization.
* If you wish to reuse the existing app for a faster run, set the property to
* `false`.
*/
reinstallApp?: boolean;
/**
* If you wish to run multiple "detox test" commands in parallel,
* make sure they don't delete the shared lock file – only the
* first command should reset the lock file.
*
* @default false
*/
keepLockFile?: boolean;
};
launchApp?: 'auto' | 'manual';
cleanup?: {
shutdownDevice?: boolean;
};
}

interface DetoxLoggerConfig {
level?: DetoxLogLevel;
/**
* @default 'sandbox'
*/
overrideConsole?: 'all' | 'sandbox' | 'none';
options?: BunyanDebugStreamOptions | ((config: Partial<DetoxLoggerConfig>) => BunyanDebugStreamOptions);
}

interface DetoxSessionConfig {
autoStart?: boolean;
debugSynchronization?: number;
server?: string;
sessionId?: string;
}

interface DetoxTestRunnerConfig {
args?: {
/**
* The command to use for runner: 'jest', 'nyc jest',
*/
$0: string;
/**
* The positional arguments to pass to the runner.
*/
_?: string[];
/**
* Any other properties recognized by test runner
*/
[prop: string]: unknown;
};
/**
* Configuration of custom integration features
* between Detox and Jest
*/
jest?: {
/**
* Device init timeout
*/
initTimeout?: number | undefined;
/**
* Insist on CLI-based retry mechanism even when the failed tests have been handled
* by jest.retryTimes(n) mechanism from Jest Circus.
*/
retryAfterCircusRetries?: boolean;
reportSpecs?: boolean | undefined;
reportWorkerAssign?: boolean | undefined;
};
/**
* Retries count. Zero means a single attempt to run tests.
*/
retries?: number;
/**
* Custom handler to process --inspect-brk CLI flag.
* Use it when you rely on another test runner than Jest.
*/
inspectBrk?: boolean | ((config: DetoxTestRunnerConfig) => void);
}

type DetoxAppConfig = (DetoxBuiltInAppConfig | DetoxCustomAppConfig) & {
/**
* App name to use with device.selectApp(appName) calls.
Expand Down Expand Up @@ -161,10 +210,6 @@ declare global {
enabled?: boolean;
}

interface DetoxTimelineArtifactsPluginConfig {
enabled?: boolean;
}

type DetoxBuiltInAppConfig = (DetoxIosAppConfig | DetoxAndroidAppConfig);

interface DetoxIosAppConfig {
Expand Down Expand Up @@ -216,7 +261,7 @@ declare global {
type: 'android.emulator';
device: string | { avdName: string };
bootArgs?: string;
gpuMode?: 'auto' | 'host' | 'swiftshader_indirect' | 'angle_indirect' | 'guest';
gpuMode?: 'auto' | 'host' | 'swiftshader_indirect' | 'angle_indirect' | 'guest' | 'off';
headless?: boolean;
/**
* @default true
Expand Down Expand Up @@ -265,51 +310,111 @@ declare global {

// endregion DetoxConfig

// Detox exports all methods from detox global and all of the global constants.
interface DetoxInstance {
device: Device;
element: ElementFacade;
waitFor: WaitForFacade;
expect: ExpectFacade;
by: ByFacade;
web: WebFacade;
}
interface DetoxExportWrapper {
readonly device: Device;

interface DetoxExportWrapper extends DetoxInstance {
/**
* The setup phase happens inside detox.init(). This is the phase where detox reads its configuration, starts a server, loads its expection library and starts a simulator
*
* @param configOverride - this object is deep-merged with the selected Detox configuration from .detoxrc
* @example
* beforeAll(async () => {
* await detox.init();
* });
*/
init(configOverride?: Partial<DetoxConfig>): Promise<void>;
readonly element: ElementFacade;

readonly waitFor: WaitForFacade;

readonly expect: ExpectFacade;

readonly by: ByFacade;

beforeEach(...args: any[]): Promise<void>;
readonly web: WebFacade;

afterEach(...args: any[]): Promise<void>;
readonly DetoxConstants: {
userNotificationTriggers: {
push: 'push';
calendar: 'calendar';
timeInterval: 'timeInterval';
location: 'location';
};
userActivityTypes: {
searchableItem: string;
browsingWeb: string;
},
searchableItemActivityIdentifier: string;
};

/**
* The cleanup phase should happen after all the tests have finished.
* This is the phase where the Detox server shuts down.
*
* @example
* after(async () => {
* await detox.cleanup();
* });
* Detox logger instance. Can be used for saving user logs to the general log file.
*/
cleanup(): Promise<void>;
readonly log: Logger;

/**
* Unstable. API to access an assembled detox config before it gets passed to testRunner
* or detox.init(). Use it only if you don't have another option.
* @internal
* @deprecated
*
* Deprecated - use {@link Detox.Logger#trace}
* Detox tracer instance. Can be used for building timelines in Google Event Tracing format.
*/
readonly trace: {
/** @deprecated */
readonly startSection: (name: string) => void;
/** @deprecated */
readonly endSection: (name: string) => void;
};

/**
* @deprecated
*/
hook(event: 'UNSAFE_configReady', listener: (config: unknown) => void): void;
readonly traceCall: <T>(event: string, action: () => Promise<T>) => Promise<T>;
}

interface Logger {
readonly level: DetoxLogLevel;

readonly fatal: _LogMethod;
readonly error: _LogMethod;
readonly warn: _LogMethod;
readonly info: _LogMethod;
readonly debug: _LogMethod;
readonly trace: _LogMethod;

child(context?: Partial<LogEvent>): Logger;
}

/** @internal */
interface _LogMethod extends _LogMethodSignature {
readonly begin: _LogMethodSignature;
readonly complete: _CompleteMethodSignature;
readonly end: _LogMethodSignature;
}

/** @internal */
interface _LogMethodSignature {
(...args: unknown[]): void
(event: LogEvent, ...args: unknown[]): void;
}

/** @internal */
interface _CompleteMethodSignature {
<T>(message: string, action: T | (() => T)): T;
<T>(event: LogEvent, message: string, action: T | (() => T)): T;
}

type LogEvent = {
/** Use when there's a risk of logging several parallel duration events. */
id?: string | number;
/** Optional. Event categories (tags) to facilitate filtering. */
cat?: string | string[];
/** Optional. Color name (applicable in Google Chrome Trace Format) */
cname?: string;

/** Reserved property. Process ID. */
pid?: never;
/** Reserved property. Thread ID. */
tid?: never;
/** Reserved property. Timestamp. */
ts?: never;
/** Reserved property. Event phase. */
ph?: never;

[customProperty: string]: unknown;
};

type DetoxLogLevel = 'fatal' | 'error' | 'warn' | 'info' | 'debug' | 'trace';

type Point2D = {
x: number,
y: number,
Expand Down Expand Up @@ -396,12 +501,10 @@ declare global {
* Holds the environment-unique ID of the device - namely, the adb ID on Android (e.g. emulator-5554) and the Mac-global simulator UDID on iOS,
* as used by simctl (e.g. AAAAAAAA-BBBB-CCCC-DDDD-EEEEEEEEEEEE).
*
* The value will be undefined until the device is properly prepared (i.e. in detox.init())
*/
id: string;
/**
* Holds a descriptive name of the device. Example: emulator-5554 (Pixel_API_29)
* The value will be undefined until the device is properly prepared (i.e. in detox.init()).
*/
name: string;

Expand Down
1 change: 1 addition & 0 deletions detox/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = require('./src/realms');

0 comments on commit 6ff7c41

Please sign in to comment.