diff --git a/.github/workflows/e2e-linux.yml b/.github/workflows/e2e-linux.yml index 746ddb1795..ccdc268300 100644 --- a/.github/workflows/e2e-linux.yml +++ b/.github/workflows/e2e-linux.yml @@ -16,6 +16,7 @@ jobs: ELECTRON_CUSTOM_VERSION: 23.0.0 DISPLAY: ":99.0" TEST_MODE: true + IS_CI: true steps: - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 diff --git a/.github/workflows/e2e-mac.yml b/.github/workflows/e2e-mac.yml index 97dcbdfe00..cc363591a2 100644 --- a/.github/workflows/e2e-mac.yml +++ b/.github/workflows/e2e-mac.yml @@ -9,6 +9,7 @@ jobs: ELECTRON_CUSTOM_VERSION: 23.0.0 TEST_MODE: true IS_E2E: true + IS_CI: true steps: - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 diff --git a/.github/workflows/e2e-win.yml b/.github/workflows/e2e-win.yml index 98ec12837e..3c6b32f20e 100644 --- a/.github/workflows/e2e-win.yml +++ b/.github/workflows/e2e-win.yml @@ -11,6 +11,7 @@ jobs: ELECTRON_CUSTOM_VERSION: 23.0.0 TEST_MODE: true E2E: true + IS_CI: true steps: - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 diff --git a/CHANGELOG.md b/CHANGELOG.md index 97d8f51fa0..46d49d5ef6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,10 +2,18 @@ # New features: +* Adds connection status information to messages panel on desktop when no peers are connected ([#1706](https://github.com/TryQuiet/quiet/issues/1706) + # Refactorings: +* Logging from all sources can be written to node console + # Fixes: +# Chores + +* Cleanup data directory at end of e2e tests + [2.2.0] # New features: @@ -15,20 +23,18 @@ # Refactorings: * Use ack for CREATE_NETWORK and simplify -* Logging from all sources can be written to node console * Move Community model to the backend # Fixes: * Allow JPEG and GIF files as profile photos ([#2332](https://github.com/TryQuiet/quiet/issues/2332)) * Fixes issues with recreating general channel when deleted while offline ([#2334](https://github.com/TryQuiet/quiet/issues/2334)) +* Fix issues with recreating general channel when deleted while offline ([#2334](https://github.com/TryQuiet/quiet/issues/2334)) +* Fix package.json license inconsistency # New Features -* Adds connection status information to messages panel on desktop when no peers are connected ([#1706](https://github.com/TryQuiet/quiet/ * Add utilities for emoji detection in messages and make all-emoji message larger font size ([#519](https://github.com/TryQuiet/quiet/issues/519)) -* Fix issues with recreating general channel when deleted while offline ([#2334](https://github.com/TryQuiet/quiet/issues/2334)) -* Fix package.json license inconsistency [2.1.2] diff --git a/packages/backend/package-lock.json b/packages/backend/package-lock.json index 72b65f7167..2697f66df2 100644 --- a/packages/backend/package-lock.json +++ b/packages/backend/package-lock.json @@ -26,6 +26,7 @@ "dotenv": "8.2.0", "events": "^3.2.0", "express": "^4.17.1", + "fastq": "^1.17.1", "get-port": "^5.1.1", "go-ipfs": "npm:mocked-go-ipfs@0.17.0", "http-server": "^0.12.3", @@ -10816,6 +10817,23 @@ "node": ">= 4.9.1" } }, + "node_modules/fastq": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fastq/node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, "node_modules/fb-watchman": { "version": "2.0.1", "license": "Apache-2.0", @@ -30783,6 +30801,21 @@ "version": "1.0.16", "dev": true }, + "fastq": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "requires": { + "reusify": "^1.0.4" + }, + "dependencies": { + "reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==" + } + } + }, "fb-watchman": { "version": "2.0.1", "requires": { diff --git a/packages/backend/package.json b/packages/backend/package.json index 58e01cc76f..87312a5a6e 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -108,6 +108,7 @@ "dotenv": "8.2.0", "events": "^3.2.0", "express": "^4.17.1", + "fastq": "^1.17.1", "get-port": "^5.1.1", "go-ipfs": "npm:mocked-go-ipfs@0.17.0", "http-server": "^0.12.3", diff --git a/packages/backend/src/nest/connections-manager/connections-manager.service.tor.spec.ts b/packages/backend/src/nest/connections-manager/connections-manager.service.tor.spec.ts index eb5d3e9ee1..98d717762b 100644 --- a/packages/backend/src/nest/connections-manager/connections-manager.service.tor.spec.ts +++ b/packages/backend/src/nest/connections-manager/connections-manager.service.tor.spec.ts @@ -31,6 +31,7 @@ import waitForExpect from 'wait-for-expect' import { Libp2pEvents } from '../libp2p/libp2p.types' import { sleep } from '../common/sleep' import { createLibp2pAddress } from '@quiet/common' +import { lib } from 'crypto-js' jest.setTimeout(100_000) diff --git a/packages/backend/src/nest/connections-manager/connections-manager.service.ts b/packages/backend/src/nest/connections-manager/connections-manager.service.ts index 07cd25bd8c..8d3b926025 100644 --- a/packages/backend/src/nest/connections-manager/connections-manager.service.ts +++ b/packages/backend/src/nest/connections-manager/connections-manager.service.ts @@ -519,7 +519,7 @@ export class ConnectionsManagerService extends EventEmitter implements OnModuleI agent: this.socksProxyAgent, localAddress: this.libp2pService.createLibp2pAddress(onionAddress, peerId.toString()), targetPort: this.ports.libp2pHiddenService, - peers: peers ?? [], + peers: peers ? peers.slice(1) : [], psk: Libp2pService.generateLibp2pPSK(community.psk).fullKey, } await this.libp2pService.createInstance(params) diff --git a/packages/backend/src/nest/libp2p/libp2p.service.spec.ts b/packages/backend/src/nest/libp2p/libp2p.service.spec.ts index 13ebb5f1ed..91d9d177c4 100644 --- a/packages/backend/src/nest/libp2p/libp2p.service.spec.ts +++ b/packages/backend/src/nest/libp2p/libp2p.service.spec.ts @@ -8,7 +8,7 @@ import { Libp2pEvents, Libp2pNodeParams } from './libp2p.types' import { toString as uint8ArrayToString } from 'uint8arrays/to-string' import validator from 'validator' import waitForExpect from 'wait-for-expect' -import { ProcessInChunksService } from './process-in-chunks.service' +import { DEFAULT_NUM_TRIES, ProcessInChunksService } from './process-in-chunks.service' describe('Libp2pService', () => { let module: TestingModule @@ -93,10 +93,12 @@ describe('Libp2pService', () => { await libp2pService.createInstance(params) expect(libp2pService.libp2pInstance).not.toBeNull() // @ts-expect-error processItem is private - const dialPeerSpy = jest.spyOn(processInChunks, 'processItem') + const processItemSpy = jest.spyOn(processInChunks, 'processItem') + const dialSpy = jest.spyOn(libp2pService.libp2pInstance!, 'dial') libp2pService.emit(Libp2pEvents.DIAL_PEERS, addresses) await waitForExpect(async () => { - expect(dialPeerSpy).toBeCalledTimes(1) + expect(processItemSpy).toBeCalledTimes(2 * DEFAULT_NUM_TRIES) + expect(dialSpy).toBeCalledTimes(1) }) }) }) diff --git a/packages/backend/src/nest/libp2p/process-in-chunks.service.ts b/packages/backend/src/nest/libp2p/process-in-chunks.service.ts index 2e7b30588b..e57e681227 100644 --- a/packages/backend/src/nest/libp2p/process-in-chunks.service.ts +++ b/packages/backend/src/nest/libp2p/process-in-chunks.service.ts @@ -1,12 +1,22 @@ import { EventEmitter } from 'events' +import fastq from 'fastq' +import type { queue, done } from 'fastq' + import Logger from '../common/logger' const DEFAULT_CHUNK_SIZE = 10 +export const DEFAULT_NUM_TRIES = 2 + +type ProcessTask = { + data: T + tries: number +} export class ProcessInChunksService extends EventEmitter { private isActive: boolean - private data: T[] + private data: Set = new Set() private chunkSize: number + private taskQueue: queue> private processItem: (arg: T) => Promise private readonly logger = Logger(ProcessInChunksService.name) constructor() { @@ -14,43 +24,62 @@ export class ProcessInChunksService extends EventEmitter { } public init(data: T[], processItem: (arg: T) => Promise, chunkSize: number = DEFAULT_CHUNK_SIZE) { - this.data = data + this.logger(`Initializing process-in-chunks.service with peers ${JSON.stringify(data, null, 2)}`) this.processItem = processItem this.chunkSize = chunkSize + this.taskQueue = fastq(this, this.processOneItem, this.chunkSize) + this.updateData(data) + this.addToTaskQueue() } - updateData(items: T[]) { + public updateData(items: T[]) { this.logger(`Updating data with ${items.length} items`) - this.data = [...new Set(this.data.concat(items))] + this.taskQueue.pause() + items.forEach(item => this.data.add(item)) + this.addToTaskQueue() } - public async processOneItem() { - const toProcess = this.data.shift() - if (toProcess) { - try { - await this.processItem(toProcess) - } catch (e) { - this.logger(`Processing ${toProcess} failed, message:`, e.message) - } finally { - process.nextTick(async () => { - await this.processOneItem() - }) + private addToTaskQueue() { + this.logger(`Adding ${this.data.size} items to the task queue`) + for (const item of this.data) { + if (item) { + this.logger(`Adding data ${item} to the task queue`) + this.data.delete(item) + try { + this.taskQueue.push({ data: item, tries: 0 } as ProcessTask) + } catch (e) { + this.logger.error(`Error occurred while adding new task for item ${item} to the queue`, e) + this.data.add(item) + } } } } - public async process() { - this.logger(`Processing ${this.data.length} items`) - for (let i = 0; i < this.chunkSize; i++) { - // Do not wait for this promise as items should be processed simultineously - void this.processOneItem() + public async processOneItem(task: ProcessTask) { + try { + this.logger(`Processing task with data ${task.data}`) + await this.processItem(task.data) + } catch (e) { + this.logger.error(`Processing task with data ${task.data} failed`, e) + if (task.tries + 1 < DEFAULT_NUM_TRIES) { + this.logger(`Will try to re-attempt task with data ${task.data}`) + this.taskQueue.push({ ...task, tries: task.tries + 1 }) + } + } finally { + this.logger(`Done attempting to process task with data ${task.data}`) } } + public async process() { + this.logger(`Processing ${this.taskQueue.length} items`) + this.taskQueue.resume() + } + public stop() { if (this.isActive) { this.logger('Stopping initial dial') this.isActive = false + this.taskQueue.pause() } } } diff --git a/packages/backend/src/nest/libp2p/process-in-chunks.spec.ts b/packages/backend/src/nest/libp2p/process-in-chunks.spec.ts index 38979c1cf9..ce751afdf3 100644 --- a/packages/backend/src/nest/libp2p/process-in-chunks.spec.ts +++ b/packages/backend/src/nest/libp2p/process-in-chunks.spec.ts @@ -27,7 +27,7 @@ describe('ProcessInChunks', () => { processInChunks.init(['a', 'b', 'c', 'd'], mockProcessItem) await processInChunks.process() await waitForExpect(() => { - expect(mockProcessItem).toBeCalledTimes(4) + expect(mockProcessItem).toBeCalledTimes(6) }) }) @@ -43,7 +43,7 @@ describe('ProcessInChunks', () => { processInChunks.updateData(['e', 'f']) await processInChunks.process() await waitForExpect(() => { - expect(mockProcessItem).toBeCalledTimes(4) + expect(mockProcessItem).toBeCalledTimes(5) }) }) @@ -60,7 +60,7 @@ describe('ProcessInChunks', () => { processInChunks.init(['a', 'b', 'c', 'd'], mockProcessItem, chunkSize) await processInChunks.process() await waitForExpect(() => { - expect(mockProcessItem).toBeCalledTimes(4) + expect(mockProcessItem).toBeCalledTimes(2) }) }) diff --git a/packages/backend/src/nest/local-db/local-db.service.ts b/packages/backend/src/nest/local-db/local-db.service.ts index 6c85552ac8..fd36ed80d8 100644 --- a/packages/backend/src/nest/local-db/local-db.service.ts +++ b/packages/backend/src/nest/local-db/local-db.service.ts @@ -95,7 +95,21 @@ export class LocalDbService { } } - public async getSortedPeers(peers: string[] = []): Promise { + public async getSortedPeers( + peers?: string[] | undefined, + includeLocalPeerAddress: boolean = true + ): Promise { + if (!peers) { + const currentCommunity = await this.getCurrentCommunity() + if (!currentCommunity) { + throw new Error('No peers were provided and no community was found to extract peers from') + } + peers = currentCommunity.peerList + if (!peers) { + throw new Error('No peers provided and no peers found on current stored community') + } + } + const peersStats = (await this.get(LocalDBKeys.PEERS)) || {} const stats: NetworkStats[] = Object.values(peersStats) const network = await this.getNetworkInfo() @@ -103,9 +117,9 @@ export class LocalDbService { if (network) { const localPeerAddress = createLibp2pAddress(network.hiddenService.onionAddress, network.peerId.id) this.logger('Local peer', localPeerAddress) - return filterAndSortPeers(peers, stats, localPeerAddress) + return filterAndSortPeers(peers, stats, localPeerAddress, includeLocalPeerAddress) } else { - return filterAndSortPeers(peers, stats) + return filterAndSortPeers(peers, stats, undefined, includeLocalPeerAddress) } } diff --git a/packages/common/src/dir.ts b/packages/common/src/dir.ts new file mode 100644 index 0000000000..4130a7ed4d --- /dev/null +++ b/packages/common/src/dir.ts @@ -0,0 +1,19 @@ +import path from 'path' +import { DESKTOP_DATA_DIR, DESKTOP_DEV_DATA_DIR } from './static' + +export type GetDataAppPathDefaults = { + appDataPath?: string + dataDir?: string +} + +export const getAppDataPath = (defaults: GetDataAppPathDefaults = {}): string => { + const defaultAppDataPath = defaults.appDataPath || process.env.APPDATA + const defaultDataDir = defaults.dataDir || process.env.DATA_DIR + + const dataPath = + defaultAppDataPath || + (process.platform === 'darwin' ? process.env.HOME + '/Library/Application Support' : process.env.HOME + '/.config') + const appPath = defaultDataDir || (process.env.NODE_ENV === 'development' ? DESKTOP_DEV_DATA_DIR : DESKTOP_DATA_DIR) + + return path.join(dataPath, appPath) +} diff --git a/packages/common/src/index.ts b/packages/common/src/index.ts index f15cd34520..81cc0eb155 100644 --- a/packages/common/src/index.ts +++ b/packages/common/src/index.ts @@ -11,3 +11,4 @@ export * from './libp2p' export * from './tests' export * from './auth' export * from './messages' +export * from './dir' diff --git a/packages/common/src/sortPeers.ts b/packages/common/src/sortPeers.ts index bf527eebe4..634a79cfaf 100644 --- a/packages/common/src/sortPeers.ts +++ b/packages/common/src/sortPeers.ts @@ -1,5 +1,4 @@ import { type NetworkStats } from '@quiet/types' -import { isDefined } from './helpers' import { filterValidAddresses } from './libp2p' /** @@ -14,9 +13,11 @@ This is the very simple algorithm for evaluating the most wanted peers. export const filterAndSortPeers = ( peersAddresses: string[], stats: NetworkStats[], - localPeerAddress?: string + localPeerAddress?: string, + includeLocalPeerAddress: boolean = true ): string[] => { peersAddresses = filterValidAddresses(peersAddresses) + const currentlyConnected = [...stats].filter(peer => peer.connectionTime === 0) const lastSeenSorted = [...stats].sort((a, b) => { return b.lastSeen - a.lastSeen }) @@ -24,7 +25,7 @@ export const filterAndSortPeers = ( return b.connectionTime - a.connectionTime }) - const mostWantedPeers: NetworkStats[] = [] + const mostWantedPeers: NetworkStats[] = currentlyConnected for (let i = 0; i < stats.length; i++) { const peerOne = lastSeenSorted[i] @@ -39,22 +40,28 @@ export const filterAndSortPeers = ( } } - const peerList = mostWantedPeers.map(peer => { - return peersAddresses.find(peerAddress => { + const peerSet: Set = new Set() + if (includeLocalPeerAddress && localPeerAddress) { + peerSet.add(localPeerAddress) + } + + mostWantedPeers.forEach(peer => { + const found = peersAddresses.find(peerAddress => { const id = peerAddress.split('/')[7] if (id === peer.peerId) { peersAddresses.splice(peersAddresses.indexOf(peerAddress), 1) return true } }) + if (found && found !== '') { + peerSet.add(found) + } + }) + peersAddresses.forEach(peerAddress => { + if (!peerSet.has(peerAddress)) { + peerSet.add(peerAddress) + } }) - return [ - ...new Set([ - localPeerAddress, // Set local peer as first - ...peerList.concat(peersAddresses), - ]), - ] - .filter(address => address !== null && address !== '') - .filter(isDefined) + return [...peerSet] } diff --git a/packages/desktop/src/renderer/store/reducers.ts b/packages/desktop/src/renderer/store/reducers.ts index 2cea0e75a8..8d987605e1 100644 --- a/packages/desktop/src/renderer/store/reducers.ts +++ b/packages/desktop/src/renderer/store/reducers.ts @@ -27,17 +27,11 @@ import { navigationReducer } from './navigation/navigation.slice' import appHandlers from './handlers/app' import { Store } from '../sagas/store.types' -import { DESKTOP_DATA_DIR, DESKTOP_DEV_DATA_DIR } from '@quiet/common' - -const dataPath = - process.env.APPDATA || - (process.platform === 'darwin' ? process.env.HOME + '/Library/Application Support' : process.env.HOME + '/.config') -const appPath = - process.env.DATA_DIR || (process.env.NODE_ENV === 'development' ? DESKTOP_DEV_DATA_DIR : DESKTOP_DATA_DIR) +import { getAppDataPath } from '@quiet/common' const options = { projectName: 'quiet', - cwd: path.join(dataPath, appPath), + cwd: getAppDataPath(), } const store = new ElectronStore(options) diff --git a/packages/e2e-tests/src/selectors.ts b/packages/e2e-tests/src/selectors.ts index 4f247cbd38..2c4c986f4a 100644 --- a/packages/e2e-tests/src/selectors.ts +++ b/packages/e2e-tests/src/selectors.ts @@ -70,6 +70,14 @@ export class App { console.log('App closed', this.buildSetup.dataDir) } + async cleanup() { + console.log(`Performing app cleanup`, this.buildSetup.dataDir) + if (this.isOpened) { + throw new Error(`App with dataDir ${this.buildSetup.dataDir} is still open, close before cleaning up!`) + } + this.buildSetup.clearDataDir() + } + get saveStateButton() { return this.driver.wait(until.elementLocated(By.xpath('//div[@data-testid="save-state-button"]'))) } diff --git a/packages/e2e-tests/src/tests/backwardsCompatibility.test.ts b/packages/e2e-tests/src/tests/backwardsCompatibility.test.ts index 25c9c5a55e..fe26656579 100644 --- a/packages/e2e-tests/src/tests/backwardsCompatibility.test.ts +++ b/packages/e2e-tests/src/tests/backwardsCompatibility.test.ts @@ -45,6 +45,9 @@ describe('Backwards Compatibility', () => { afterAll(async () => { await new Promise(resolve => setTimeout(() => resolve(), 5000)) await ownerAppNewVersion?.close() + await ownerAppNewVersion?.cleanup() + await ownerAppOldVersion?.close() + await ownerAppOldVersion?.cleanup() }) describe('User opens app for the first time', () => { it('Owner opens the app', async () => { diff --git a/packages/e2e-tests/src/tests/invitationLink.test.ts b/packages/e2e-tests/src/tests/invitationLink.test.ts index be91beb23b..8e7e00686d 100644 --- a/packages/e2e-tests/src/tests/invitationLink.test.ts +++ b/packages/e2e-tests/src/tests/invitationLink.test.ts @@ -34,7 +34,9 @@ describe('New user joins using invitation link while having app opened', () => { afterAll(async () => { await ownerApp?.close() + await ownerApp?.cleanup() await guestApp?.close() + await guestApp?.cleanup() }) describe('Stages:', () => { diff --git a/packages/e2e-tests/src/tests/multipleClients.test.ts b/packages/e2e-tests/src/tests/multipleClients.test.ts index 6cd7f14059..963a7d5920 100644 --- a/packages/e2e-tests/src/tests/multipleClients.test.ts +++ b/packages/e2e-tests/src/tests/multipleClients.test.ts @@ -73,6 +73,7 @@ describe('Multiple Clients', () => { afterAll(async () => { for (const user of Object.values(users)) { await user.app.close() + await user.app.cleanup() } }) diff --git a/packages/e2e-tests/src/tests/oneClient.test.ts b/packages/e2e-tests/src/tests/oneClient.test.ts index 9c873571ce..f3efe6bb4c 100644 --- a/packages/e2e-tests/src/tests/oneClient.test.ts +++ b/packages/e2e-tests/src/tests/oneClient.test.ts @@ -27,6 +27,7 @@ describe('One Client', () => { afterAll(async () => { await app.close() + await app.cleanup() }) describe('User opens app for the first time', () => { it('Get opened app process data', () => { diff --git a/packages/e2e-tests/src/tests/userProfile.test.ts b/packages/e2e-tests/src/tests/userProfile.test.ts index 024550fa4a..1c72eb8d9a 100644 --- a/packages/e2e-tests/src/tests/userProfile.test.ts +++ b/packages/e2e-tests/src/tests/userProfile.test.ts @@ -50,6 +50,7 @@ describe('User Profile Feature', () => { afterAll(async () => { for (const user of Object.values(users)) { await user.app.close() + await user.app.cleanup() } }) diff --git a/packages/e2e-tests/src/utils.ts b/packages/e2e-tests/src/utils.ts index 671e32a92b..eee6757a32 100644 --- a/packages/e2e-tests/src/utils.ts +++ b/packages/e2e-tests/src/utils.ts @@ -4,8 +4,8 @@ import { type SupportedPlatformDesktop } from '@quiet/types' import getPort from 'get-port' import path from 'path' import fs from 'fs' -import { DESKTOP_DATA_DIR } from '@quiet/common' import { RetryConfig, TimeoutMetadata } from './types' +import { DESKTOP_DATA_DIR, getAppDataPath } from '@quiet/common' export const BACKWARD_COMPATIBILITY_BASE_VERSION = '2.0.1' // Pre-latest production version const appImagesPath = `${__dirname}/../Quiet` @@ -23,6 +23,7 @@ export class BuildSetup { public port?: number public debugPort?: number public dataDir?: string + public dataDirPath: string private child?: ChildProcessWithoutNullStreams private defaultDataDir: boolean private fileName?: string @@ -37,6 +38,7 @@ export class BuildSetup { if (!this.dataDir) { this.dataDir = `e2e_${(Math.random() * 10 ** 18).toString(36)}` } + this.dataDirPath = getAppDataPath({ dataDir: this.dataDir }) } async initPorts() { @@ -225,6 +227,15 @@ export class BuildSetup { await this.driver?.close() } + public clearDataDir() { + if (process.env.IS_CI === 'true') { + console.warn('Not deleting data directory because we are running in CI') + return + } + console.log(`Deleting data directory at ${this.dataDirPath}`) + fs.rmdirSync(this.dataDirPath, { recursive: true }) + } + public getProcessData = () => { let dataDirPath = '' let resourcesPath = ''