Skip to content

Commit

Permalink
feat: unified artifacts handling (#2)
Browse files Browse the repository at this point in the history
  • Loading branch information
noomorph committed May 4, 2024
1 parent a0f9be8 commit 802d4ea
Show file tree
Hide file tree
Showing 14 changed files with 208 additions and 6 deletions.
21 changes: 16 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,30 @@

## Prerequisites

To use Detox, Jest, and Allure together, please verify that the following modules are part of your `devDependencies` in your `package.json` file.
To use Detox, Jest, and Allure together, please verify that the following modules are part of your `devDependencies` in your `package.json` file.

```json
"devDependencies": {
"detox": "^20.14.7",
"detox-allure2-adapter": "^1.0.0-alpha.3",
"detox": "^20.20.3",
"detox-allure2-adapter": "^1.0.0-alpha.4",
"jest": "^29.7.0",
"jest-allure2-reporter": "^2.0.0-beta.5",
"jest-metadata": "^1.3.1"
"jest-allure2-reporter": "^2.0.0-beta.15",
"jest-metadata": "^1.5.2"
}
```

If not, add the necessary modules and run `npm install`.

## Setting Up `detox.config.js`

Find `.detoxrc.json`, `detox.config.js` or where your Detox configuration is stored. Add "extends" to include this adapter's preset:

```json
{
"extends": "detox-allure2-adapter/preset-detox"
}
```

## Setting Up `jest.config.js`

A configuration file for Jest named `jest.config.js` needs to be present. Add or update the following sections:
Expand All @@ -26,6 +36,7 @@ module.exports = {
reporters: [
'detox/runners/jest/reporter',
['jest-allure2-reporter', {
extends: 'detox-allure2-adapter/preset-allure',
/* see https://github.com/wix-incubator/jest-allure2-reporter/blob/beta/index.d.ts */
}],
],
Expand Down
12 changes: 12 additions & 0 deletions package-e2e/test.cjs
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
const assert = require('assert');
const listener = require('detox-allure2-adapter');
assert(typeof listener === 'function', 'detox-allure2-adapter should have a function as its default export');

const DetoxAllurePathBuilder = require('detox-allure2-adapter/path-builder');
assert(typeof DetoxAllurePathBuilder === 'function', 'detox-allure2-adapter/path-builder should have a class as its default export');
assert(new DetoxAllurePathBuilder instanceof DetoxAllurePathBuilder, 'detox-allure2-adapter/path-builder should have a class as its default export');

const presetAllure = require('detox-allure2-adapter/preset-allure');
assert(typeof presetAllure === 'object', 'detox-allure2-adapter/preset-allure should have an object as its default export');
assert(typeof presetAllure.testCase === 'object', 'detox-allure2-adapter/preset-allure should have an object as its default export');

const presetDetox = require('detox-allure2-adapter/preset-detox');
assert(typeof presetDetox === 'object', 'detox-allure2-adapter/preset-detox should have an object as its default export');
assert(typeof presetDetox.artifacts === 'object', 'detox-allure2-adapter/preset-detox should have an object as its default export');
12 changes: 12 additions & 0 deletions package-e2e/test.mjs
Original file line number Diff line number Diff line change
@@ -1,4 +1,16 @@
import assert from 'assert';
import listener from 'detox-allure2-adapter';
import DetoxAllurePathBuilder from 'detox-allure2-adapter/path-builder';
import presetAllure from 'detox-allure2-adapter/preset-allure';
import presetDetox from 'detox-allure2-adapter/preset-detox';

assert(typeof listener === 'function', 'detox-allure2-adapter should have a function as its default export');

assert(typeof DetoxAllurePathBuilder === 'function', 'detox-allure2-adapter/path-builder should have a class as its default export');
assert(new DetoxAllurePathBuilder instanceof DetoxAllurePathBuilder, 'detox-allure2-adapter/path-builder should have a class as its default export');

assert(typeof presetAllure === 'object', 'detox-allure2-adapter/preset-allure should have an object as its default export');
assert(typeof presetAllure.testCase === 'object', 'detox-allure2-adapter/preset-allure should have an object as its default export');

assert(typeof presetDetox === 'object', 'detox-allure2-adapter/preset-detox should have an object as its default export');
assert(typeof presetDetox.artifacts === 'object', 'detox-allure2-adapter/preset-detox should have an object as its default export');
7 changes: 7 additions & 0 deletions package-e2e/test.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
import type { ReporterOptions } from 'jest-allure2-reporter';

import listener from 'detox-allure2-adapter';
import DetoxAllurePathBuilder from 'detox-allure2-adapter/path-builder';
import presetAllure from 'detox-allure2-adapter/preset-allure';
import presetDetox from 'detox-allure2-adapter/preset-detox';
import { EnvironmentListenerFn } from 'jest-environment-emit';

function assertType<T>(_actual: T): void {
// no-op
}

assertType<EnvironmentListenerFn>(listener);
assertType<DetoxAllurePathBuilder>(new DetoxAllurePathBuilder());
assertType<ReporterOptions>(presetAllure);
17 changes: 16 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,21 @@
"require": "./index.js",
"types": "./dist/index.d.ts"
},
"./path-builder": {
"import": "./path-builder.mjs",
"require": "./path-builder.js",
"types": "./dist/path-builder.d.ts"
},
"./preset-allure": {
"import": "./preset-allure.mjs",
"require": "./preset-allure.js",
"types": "./dist/preset/allure.d.ts"
},
"./preset-detox": {
"import": "./preset-detox.mjs",
"require": "./preset-detox.js",
"types": "./dist/preset/detox.d.ts"
},
"./package.json": "./package.json"
},
"engines": {
Expand Down Expand Up @@ -57,7 +72,7 @@
"homepage": "https://github.com/wix-incubator/detox-allure2-adapter#readme",
"peerDependencies": {
"detox": "20.14.2-smoke.0 || >20.14.5",
"jest-allure2-reporter": "^2.0.0-beta.5"
"jest-allure2-reporter": "^2.0.0-beta.15"
},
"devDependencies": {
"@commitlint/cli": "^17.4.2",
Expand Down
1 change: 1 addition & 0 deletions path-builder.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = require('./dist/path-builder').default;
5 changes: 5 additions & 0 deletions path-builder.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import index from './dist/path-builder.js';

const { default: PathBuilder } = index;

export default PathBuilder;
1 change: 1 addition & 0 deletions preset-allure.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = require('./dist/preset/allure').default;
5 changes: 5 additions & 0 deletions preset-allure.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import index from './dist/preset/allure.js';

const { default: preset } = index;

export default preset;
1 change: 1 addition & 0 deletions preset-detox.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
module.exports = require('./dist/preset/detox').default;
5 changes: 5 additions & 0 deletions preset-detox.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import index from './dist/preset/detox.js';

const { default: preset } = index;

export default preset;
21 changes: 21 additions & 0 deletions src/path-builder.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import crypto from 'node:crypto';
import fs from 'node:fs';
import os from 'node:os';
import path from 'node:path';

export default class DetoxAllurePathBuilder {
#temporaryDirectory: string;

constructor() {
this.#temporaryDirectory = fs.mkdtempSync(os.tmpdir() + path.sep + 'detox-artifacts-');
}

/** @returns {string} */
buildPathForTestArtifact(artifactName: string) {
return path.join(
this.#temporaryDirectory,
crypto.randomBytes(16).toString('hex'),
artifactName,
);
}
}
83 changes: 83 additions & 0 deletions src/preset/allure.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
// eslint-disable-next-line import/no-internal-modules
import { config, session } from 'detox/internals';
import type {
KeyedParameterCustomizer,
ReporterOptions,
TestCaseCustomizer,
TestCaseExtractorContext,
} from 'jest-allure2-reporter';

const historyId: TestCaseCustomizer['historyId'] = ({ value }): string => {
const { type } = config.device;
const platform = type.split('.')[0];
return `${platform}:${value}`;
};

const device: KeyedParameterCustomizer<unknown> = (): string | undefined => {
const { type, device } = config.device as any;

switch (type) {
case 'ios.simulator': {
return [device.type, device.os].filter(Boolean).join(', ') || 'iOS Simulator';
}
case 'android.emulator': {
return device.avdName || 'Android Emulator';
}
case 'android.genycloud': {
return device.recipeName || 'Genymotion SaaS';
}
default: {
return;
}
}
};

const status: TestCaseCustomizer<TestCaseExtractorContext>['status'] = ({
testCase: { failureMessages },
value,
}) => {
if (value !== 'broken') {
return value;
}

return failureMessages.every((x) => x.includes('Test Failed:')) ? 'failed' : 'broken';
};

const options: ReporterOptions = {
resultsDir: config.artifacts?.rootDir ?? 'artifacts',
overwrite: session.testSessionIndex === 0,
attachments: {
fileHandler: 'copy',
},
testCase: {
historyId,
status,
parameters: {
device,
},
},
testFile: {
historyId,
parameters: {
device,
},
},
testRun: {
ignored: ({ aggregatedResult }) =>
aggregatedResult.numFailedTests === 0 && aggregatedResult.numFailedTestSuites === 0,
attachments: [
{
name: 'detox.log',
type: 'text/plain',
source: 'detox.log',
},
{
name: 'detox.trace.json',
type: 'application/json',
source: 'detox.trace.json',
},
],
},
};

export default options;
23 changes: 23 additions & 0 deletions src/preset/detox.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
const config: Partial<Detox.DetoxConfig> = {
artifacts: {
rootDir: 'artifacts/',
pathBuilder: 'detox-allure2-adapter/path-builder',
plugins: {
log: 'failing',
screenshot: {
enabled: true,
keepOnlyFailedTestsArtifacts: true,
shouldTakeAutomaticSnapshots: true,
takeWhen: {
testStart: false,
testFailure: true,
testDone: false,
appNotReady: true,
},
},
uiHierarchy: 'enabled',
},
},
};

export default config as object;

0 comments on commit 802d4ea

Please sign in to comment.