Skip to content

Replace node-module 'tempfile' seamlessly with 'tmp' #4777

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jun 11, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion detox/__tests__/helpers.js
Original file line number Diff line number Diff line change
@@ -2,9 +2,10 @@ const path = require('path');

const fs = require('fs-extra');
const _ = require('lodash');
const tempfile = require('tempfile');
const yargs = require('yargs');

const tempfile = require('../src/utils/tempfile');

function callCli(modulePath, cmd) {
return new Promise((resolve, reject) => {
const originalModule = require(path.join(__dirname, '../local-cli', modulePath));
4 changes: 2 additions & 2 deletions detox/local-cli/build.test.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
const tempfile = require('tempfile');

const { callCli } = require('../__tests__/helpers');
const tempfile = require('../src/utils/tempfile');


describe('build', () => {
let execSync, detox;
3 changes: 2 additions & 1 deletion detox/local-cli/test.test.js
Original file line number Diff line number Diff line change
@@ -659,7 +659,8 @@ describe('CLI', () => {
// Helpers

function tempfile(extension, content) {
const tempFilePath = require('tempfile')(extension);
const _tempfile = require('../src/utils/tempfile');
const tempFilePath = _tempfile(extension);

fs.ensureFileSync(tempFilePath);
if (content) {
2 changes: 1 addition & 1 deletion detox/package.json
Original file line number Diff line number Diff line change
@@ -98,7 +98,7 @@
"stream-json": "^1.7.4",
"strip-ansi": "^6.0.1",
"telnet-client": "1.2.8",
"tempfile": "^2.0.0",
"tmp": "^0.2.1",
"trace-event-lib": "^1.3.1",
"which": "^1.3.1",
"ws": "^7.0.0",
4 changes: 2 additions & 2 deletions detox/src/android/AndroidExpect.test.js
Original file line number Diff line number Diff line change
@@ -9,7 +9,7 @@ describe('AndroidExpect', () => {

beforeEach(() => {
jest.mock('../utils/logger');
jest.mock('tempfile');
jest.mock('../utils/tempfile');
jest.mock('fs-extra');

mockExecutor = new MockExecutor();
@@ -341,7 +341,7 @@ describe('AndroidExpect', () => {
mockExecutor.executeResult = Promise.resolve(invokeResultInBase64);

fs = require('fs-extra');
tempfile = require('tempfile');
tempfile = require('../utils/tempfile');
tempfile.mockReturnValue(tempFilePath);

_element = e.element(e.by.id('FancyElement'));
3 changes: 2 additions & 1 deletion detox/src/android/core/NativeElement.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
const path = require('path');

const fs = require('fs-extra');
const tempfile = require('tempfile');


const DetoxRuntimeError = require('../../errors/DetoxRuntimeError');
const invoke = require('../../invoke');
const { removeMilliseconds } = require('../../utils/dateUtils');
const { actionDescription } = require('../../utils/invocationTraceDescriptions');
const mapLongPressArguments = require('../../utils/mapLongPressArguments');
const tempfile = require('../../utils/tempfile');
const actions = require('../actions/native');
const DetoxMatcherApi = require('../espressoapi/DetoxMatcher');
const { ActionInteraction } = require('../interactions/native');
3 changes: 2 additions & 1 deletion detox/src/artifacts/log/ios/SimulatorLogPlugin.test.js
Original file line number Diff line number Diff line change
@@ -5,9 +5,10 @@ const path = require('path');

const fs = require('fs-extra');
const _ = require('lodash');
const tempfile = require('tempfile');

const childProcess = require('../../../utils/childProcess');
const tempfile = require('../../../utils/tempfile');


describe('SimulatorLogPlugin', () => {
async function majorWorkflow() {
3 changes: 2 additions & 1 deletion detox/src/artifacts/templates/artifact/FileArtifact.js
Original file line number Diff line number Diff line change
@@ -2,9 +2,10 @@
const path = require('path');

const fs = require('fs-extra');
const tempfile = require('tempfile');

const appendFile = require('../../../utils/appendFile');
const tempfile = require('../../../utils/tempfile');


const Artifact = require('./Artifact');

Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
const fs = require('fs-extra');
const _ = require('lodash');
const tempfile = require('tempfile');

const tempfile = require('../../../utils/tempfile');

describe('FileArtifact', () => {
let FileArtifact, fileArtifact, logger, temporaryPath, temporaryData, destinationPath;
3 changes: 2 additions & 1 deletion detox/src/artifacts/utils/temporaryPath.js
Original file line number Diff line number Diff line change
@@ -3,9 +3,10 @@ const { promisify } = require('util');

const glob = require('glob');
const _ = require('lodash');
const tempfile = require('tempfile');

const { useForwardSlashes } = require('../../utils/shellUtils');
const tempfile = require('../../utils/tempfile');


const globSync = glob.sync;
const globAsync = promisify(glob);
3 changes: 2 additions & 1 deletion detox/src/artifacts/utils/temporaryPath.test.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
const path = require('path');

const fs = require('fs-extra');
const tempfile = require('tempfile');

const tempfile = require('../../utils/tempfile');

const temporaryPath = require('./temporaryPath');

3 changes: 2 additions & 1 deletion detox/src/client/Client.test.js
Original file line number Diff line number Diff line change
@@ -2,10 +2,11 @@
jest.useFakeTimers('modern');

const { serializeError } = require('serialize-error');
const tempfile = require('tempfile');


const { validSession } = require('../configuration/configurations.mock');
const Deferred = require('../utils/Deferred');
const tempfile = require('../utils/tempfile');

const actions = require('./actions/actions');

3 changes: 2 additions & 1 deletion detox/src/devices/allocation/DeviceRegistry.test.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
const fs = require('fs-extra');
const tempfile = require('tempfile');

const tempfile = require('../../utils/tempfile');

const DeviceRegistry = require('./DeviceRegistry'); // Adjust the path to your actual file

3 changes: 2 additions & 1 deletion detox/src/ios/expectTwo.js
Original file line number Diff line number Diff line change
@@ -3,14 +3,15 @@ const path = require('path');

const fs = require('fs-extra');
const _ = require('lodash');
const tempfile = require('tempfile');


const { assertTraceDescription, assertEnum, assertNormalized } = require('../utils/assertArgument');
const { removeMilliseconds } = require('../utils/dateUtils');
const { actionDescription, expectDescription } = require('../utils/invocationTraceDescriptions');
const { isRegExp } = require('../utils/isRegExp');
const log = require('../utils/logger').child({ cat: 'ws-client, ws' });
const mapLongPressArguments = require('../utils/mapLongPressArguments');
const tempfile = require('../utils/tempfile');
const traceInvocationCall = require('../utils/traceInvocationCall').bind(null, log);

const { systemElement, systemMatcher, systemExpect, isSystemElement } = require('./system');
4 changes: 2 additions & 2 deletions detox/src/ios/expectTwo.test.js
Original file line number Diff line number Diff line change
@@ -11,8 +11,8 @@ describe('expectTwo', () => {

beforeEach(() => {
jest.mock('../utils/logger');
jest.mock('../utils/tempfile');
jest.mock('fs-extra');
jest.mock('tempfile');

fs = require('fs-extra');
const IosExpect = require('./expectTwo');
@@ -690,7 +690,7 @@ describe('expectTwo', () => {
screenshotPath: deviceTmpFilePath,
});

require('tempfile').mockReturnValue(tmpFilePath);
require('../utils/tempfile').mockReturnValue(tmpFilePath);
result = await e.element(e.by.id('uniqueId')).takeScreenshot(imageName);
});

3 changes: 2 additions & 1 deletion detox/src/logger/DetoxLogger.test.js
Original file line number Diff line number Diff line change
@@ -8,9 +8,10 @@ const os = require('os');

const fs = require('fs-extra');
const _ = require('lodash');
const tempfile = require('tempfile');

const sleep = require('../utils/sleep');
const tempfile = require('../utils/tempfile');


jest.retryTimes(2);

2 changes: 1 addition & 1 deletion detox/src/logger/utils/DetoxLogFinalizer.test.js
Original file line number Diff line number Diff line change
@@ -5,9 +5,9 @@ const { PassThrough } = require('stream');

const fs = require('fs-extra');
const glob = require('glob');
const tempfile = require('tempfile');

const temporary = require('../../artifacts/utils/temporaryPath');
const tempfile = require('../../utils/tempfile');
const DetoxLogger = require('../DetoxLogger');

const DetoxLogFinalizer = require('./DetoxLogFinalizer');
3 changes: 2 additions & 1 deletion detox/src/logger/utils/streams/BunyanTransformer.test.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
const fs = require('fs-extra');
const tempfile = require('tempfile');

const tempfile = require('../../../utils/tempfile');

describe('BunyanTransformer', () => {
/** @type {import('./BunyanTransformer')} */
3 changes: 2 additions & 1 deletion detox/src/utils/ExclusiveLockfile.test.js
Original file line number Diff line number Diff line change
@@ -2,9 +2,10 @@ jest.mock('proper-lockfile');

const fs = require('fs-extra');
const plock = require('proper-lockfile');
const tempfile = require('tempfile');

const ExclusiveLockFile = require('./ExclusiveLockfile');
const tempfile = require('./tempfile');


describe('ExclusiveLockFile', () => {
let filePath;
3 changes: 2 additions & 1 deletion detox/src/utils/appendFile.test.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
const fs = require('fs-extra');
const tempfile = require('tempfile');

const appendFile = require('./appendFile');
const tempfile = require('./tempfile');


describe('appendFile', () => {
let src, dest;
3 changes: 2 additions & 1 deletion detox/src/utils/environment.test.js
Original file line number Diff line number Diff line change
@@ -3,7 +3,8 @@ const path = require('path');

const fs = require('fs-extra');
const _ = require('lodash');
const tempfile = require('tempfile');

const tempfile = require('./tempfile');

describe('Environment', () => {
let Environment;
3 changes: 2 additions & 1 deletion detox/src/utils/fsext.test.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
const path = require('path');

const fs = require('fs-extra');
const tempfile = require('tempfile');

const fsext = require('./fsext');
const tempfile = require('./tempfile');


test('isDirEmptySync', async () => {
const tempDir = tempfile();
18 changes: 18 additions & 0 deletions detox/src/utils/tempfile.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
const tmp = require('tmp');

tmp.setGracefulCleanup();

/**
* Creates a temporary file path. If extension is provided, it will be appended to the path.
* @param {string} [extension] - Optional file extension to append to the temporary file path
* @returns {string} Path to a temporary file
*/
module.exports = function(extension) {
const _extension = (extension && extension.startsWith('.'))
? extension
: (extension && `.${extension}`);

return tmp.tmpNameSync({
template: `detox-${process.pid}-XXXXXX${_extension || ''}`,
});
};
72 changes: 72 additions & 0 deletions detox/src/utils/tempfile.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
describe('tempfile', () => {
let tmp;
let tempfile;

describe('in full integration with tmp module', () => {
beforeEach(() => {
jest.restoreAllMocks();
tempfile = require('./tempfile');
});

it('should work with the real tmp module', () => {
const tmpdir = require('node:os').tmpdir();
const path = require('node:path');

const expectedFile = path.join(tmpdir, `detox-${process.pid}-[a-zA-Z0-9]+.log`).replace(/\\/g, '\\\\');
const expectedResult = new RegExp(`^${expectedFile}$`);

const result = tempfile('.log');
expect(result).toMatch(expectedResult);
});
});

describe('with mocked tmp module', () => {
beforeEach(() => {
jest.mock('tmp');
tmp = require('tmp');
tempfile = require('./tempfile');
});

const expectTmpCalled = ({ withExtension = '' } = {}) => {
const template = `detox-${process.pid}-XXXXXX${withExtension}`;
expect(tmp.tmpNameSync).toHaveBeenCalledWith({ template });
};

it(`should enable tmp's graceful cleanup`, () => {
expect(tmp.setGracefulCleanup).toHaveBeenCalled();
});

it('should return the value from tmp.tmpNameSync', () => {
const mockPath = '/tmp/detox-123-abc123';
tmp.tmpNameSync.mockReturnValueOnce(mockPath);

const result = tempfile();
expect(result).toEqual(mockPath);
});

it('should create a temporary file path without extension', () => {
tempfile();
expectTmpCalled();
});

it('should create a temporary file path with extension', () => {
tempfile('txt');
expectTmpCalled({ withExtension: '.txt' });
});

it('should handle extension with leading dot', () => {
tempfile('.txt');
expectTmpCalled({ withExtension: '.txt' });
});

it('should handle empty extension', () => {
tempfile('');
expectTmpCalled();
});

it('should handle undefined extension', () => {
tempfile();
expectTmpCalled();
});
});
});
2 changes: 1 addition & 1 deletion detox/test/integration/stub/StubRuntimeDriver.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
const temporaryPath = require('detox/src/artifacts/utils/temporaryPath');
const DeviceDriverBase = require('detox/src/devices/runtime/drivers/DeviceDriverBase');
const tempfile = require('tempfile');
const tempfile = require('../../../src/utils/tempfile');

const {
sleepSomeTime,
2 changes: 1 addition & 1 deletion detox/test/integration/timeline-artifact.test.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
const path = require('path');

const _ = require('lodash');
const tempfile = require('tempfile');
const tempfile = require('../../src/utils/tempfile');
const fs = require('fs-extra');
const { promisify } = require('util');
const { execCommand } = require('./utils/exec');

Unchanged files with check annotations Beta

});
describe('- beforeAll hooks -', () => {
it.skip('trigger false test_start glitch', () => {});

Check warning on line 14 in detox/test/e2e/23.flows.test.js

GitHub Actions / Linux

Disabled test

Check warning on line 14 in detox/test/e2e/23.flows.test.js

GitHub Actions / Linux

Disabled test
describe('inner suite', () => {
beforeAll(async () => {
await expect(faceid).toHaveText(RESULTS.DENIED);
});
// todo: Skipped due to an error coming from react-native-permissions. Fix or implement a custom check.

Check warning on line 170 in detox/test/e2e/13.permissions.test.js

GitHub Actions / Linux

Unexpected 'todo' comment without any conditions: 'todo: Skipped due to an error coming...'

Check warning on line 170 in detox/test/e2e/13.permissions.test.js

GitHub Actions / Linux

Unexpected 'todo' comment without any conditions: 'todo: Skipped due to an error coming...'
it.skip('should grant permission', async () => {

Check warning on line 171 in detox/test/e2e/13.permissions.test.js

GitHub Actions / Linux

Disabled test

Check warning on line 171 in detox/test/e2e/13.permissions.test.js

GitHub Actions / Linux

Disabled test
const permissions = { faceid: 'YES' };
await device.launchApp({ permissions, delete: true });
await expect(element(by.id('UniqueId_AnimationsScreen_afterAnimationText'))).toBeVisible();
});
it.skip(`should not wait for infinite animations`, async () => {

Check warning on line 44 in detox/test/e2e/12.animations.test.js

GitHub Actions / Linux

Disabled test

Check warning on line 44 in detox/test/e2e/12.animations.test.js

GitHub Actions / Linux

Disabled test
await _startTest(driver, { loops: -1 });
await expect(element(by.id('UniqueId_AnimationsScreen_afterAnimationText'))).toBeVisible();
});
await expect(element(by.text('From push'))).toExist();
});
xit('Init from calendar notification', async () => {

Check warning on line 14 in detox/test/e2e/11.user-notifications.test.js

GitHub Actions / Linux

Disabled test

Check warning on line 14 in detox/test/e2e/11.user-notifications.test.js

GitHub Actions / Linux

Disabled test
await device.launchApp({newInstance: true, userNotification: userNotificationCalendarTrigger});
await expect(element(by.text('From calendar'))).toExist();
});
await expect(element(by.text('From push'))).toExist();
});
xit('Background calendar notification', async () => {

Check warning on line 26 in detox/test/e2e/11.user-notifications.test.js

GitHub Actions / Linux

Disabled test

Check warning on line 26 in detox/test/e2e/11.user-notifications.test.js

GitHub Actions / Linux

Disabled test
await device.launchApp({newInstance: true});
await device.sendToHome();
await device.launchApp({newInstance: false, userNotification: userNotificationCalendarTrigger});
await expect(element(by.text('From push'))).toExist();
});
xit('Foreground calendar notifications', async () => {

Check warning on line 39 in detox/test/e2e/11.user-notifications.test.js

GitHub Actions / Linux

Disabled test

Check warning on line 39 in detox/test/e2e/11.user-notifications.test.js

GitHub Actions / Linux

Disabled test
await device.launchApp({newInstance: true});
await device.sendUserNotification(userNotificationCalendarTrigger);
await expect(element(by.text('From calendar'))).toExist();
await expect(element(by.text('I contain some text'))).toHaveId('main-text');
});
it.skip(':ios: should assert an element has (accessibility) value', async () => {

Check warning on line 49 in detox/test/e2e/04.assertions.test.js

GitHub Actions / Linux

Disabled test

Check warning on line 49 in detox/test/e2e/04.assertions.test.js

GitHub Actions / Linux

Disabled test
await expect(driver.toggleElement).toHaveValue('0');
await driver.toggleElement.tap();
await expect(driver.toggleElement).toHaveValue('1');
});
});
it.skip(':android: should throw if tap handling is too slow', async () => {

Check warning on line 99 in detox/test/e2e/03.actions.test.js

GitHub Actions / Linux

Disabled test

Check warning on line 99 in detox/test/e2e/03.actions.test.js

GitHub Actions / Linux

Disabled test
try {
await driver.sluggishTapElement.tap();
} catch (e) {
'@typescript-eslint/no-unused-vars': ['error', {argsIgnorePattern: '^_'}],
// TODO: enable these rules gradually

Check warning on line 21 in detox/test/.eslintrc.js

GitHub Actions / Linux

Unexpected 'todo' comment without any conditions: 'TODO: enable these rules gradually'

Check warning on line 21 in detox/test/.eslintrc.js

GitHub Actions / Linux

Unexpected 'todo' comment without any conditions: 'TODO: enable these rules gradually'
'comma-dangle': 0,
'curly': 0,
'eol-last': 0,
const rnVersion = (function parseRNVersion() {
let raw;
try {
const packageJson = require('react-native/package.json');

Check warning on line 6 in detox/src/utils/rn-consts/rn-consts.js

GitHub Actions / Linux

"react-native" is not published
raw = packageJson.version;
} catch {
// Default version for RN
const result = await this.withAction('scrollToView', traceDescription);
// TODO Synchronization is not perfect here. We have to fix and remove this sleep ASAP.

Check warning on line 143 in detox/src/ios/web.js

GitHub Actions / Linux

Unexpected 'todo' comment without any conditions: 'TODO Synchronization is not perfect...'
// See https://github.com/wix/Detox/issues/4741
await sleep(50);
return result;
const _ = require('lodash');
const { DetoxConfigErrorComposer } = require('../errors');

Check warning on line 3 in detox/src/configuration/collectCliConfig.js

GitHub Actions / Linux

'DetoxConfigErrorComposer' is assigned a value but never used
const argparse = require('../utils/argparse');
const asBoolean = (value) => {