diff --git a/README.md b/README.md index a0b341a..375855a 100644 --- a/README.md +++ b/README.md @@ -219,5 +219,28 @@ export const config = { // ... } ``` + +### allowMultipleReruns +Allows multiple retries when set to true. +This will clear the configured `rerunDataDir` before a test run and set the environment variable `DISABLE_RERUN = false` in the created rerun script. + +Type: `boolean` + +Default: `false` + +Example: +```js +import RerunService from 'wdio-rerun-service'; +export const config = { + // ... + services: [ + [RerunService, { + allowMultipleReruns: true + }] + ], + // ... +} +``` + ---- diff --git a/src/index.ts b/src/index.ts index 87537e8..854364f 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,6 +1,6 @@ import type { Capabilities, Frameworks, Options, Services } from '@wdio/types' import minimist from 'minimist' -import { mkdir, readdir, readFile, writeFile } from 'node:fs/promises' +import { mkdir, readdir, readFile, rm, writeFile } from 'node:fs/promises' import { join } from 'node:path' import { argv, env, platform } from 'node:process' import { v4 as uuidv4 } from 'uuid' @@ -22,6 +22,7 @@ interface RerunServiceOptions { rerunScriptPath?: string commandPrefix?: string customParameters?: string + allowMultipleReruns?: boolean } export default class RerunService implements Services.ServiceInstance { @@ -34,6 +35,7 @@ export default class RerunService implements Services.ServiceInstance { customParameters: string specFile: string disabled: boolean + allowMultipleReruns: boolean constructor(options: RerunServiceOptions = {}) { const { @@ -42,6 +44,7 @@ export default class RerunService implements Services.ServiceInstance { rerunScriptPath, commandPrefix, customParameters, + allowMultipleReruns, } = options this.nonPassingItems = [] this.serviceWorkerId = '' @@ -52,7 +55,11 @@ export default class RerunService implements Services.ServiceInstance { this.commandPrefix = commandPrefix ?? '' this.customParameters = customParameters ?? '' this.specFile = '' - this.disabled = env['DISABLE_RERUN'] === 'true' + this.disabled = + allowMultipleReruns === true + ? !allowMultipleReruns + : env['DISABLE_RERUN'] === 'true' + this.allowMultipleReruns = allowMultipleReruns ?? false } async before( @@ -63,7 +70,12 @@ export default class RerunService implements Services.ServiceInstance { return } this.specFile = specs[0] ?? '' - // console.log(`Re-run service is activated. Data directory: ${this.rerunDataDir}`); + // console.log( + // `Re-run service is activated. Data directory: ${this.rerunDataDir}`, + // ) + if (this.allowMultipleReruns) { + await rm(this.rerunDataDir, { recursive: true, force: true }); + } await mkdir(this.rerunDataDir, { recursive: true }) this.serviceWorkerId = uuidv4() } @@ -175,10 +187,12 @@ export default class RerunService implements Services.ServiceInstance { const parsedArgs = minimist(argv.slice(2)) const args = parsedArgs._[0] ? parsedArgs._[0] + ' ' : '' const prefix = this.commandPrefix ? this.commandPrefix + ' ' : '' + const disableRerunValue = String(!this.allowMultipleReruns) const disableRerun = platform === 'win32' - ? 'set DISABLE_RERUN=true &&' - : 'DISABLE_RERUN=true' + ? `set DISABLE_RERUN=${disableRerunValue} &&` + : `DISABLE_RERUN=${disableRerunValue}` + let rerunCommand = `${prefix}${disableRerun} npx wdio ${args}${this.customParameters}` const failureLocations = new Set() for (const file of rerunFiles) { diff --git a/tests/service.test.ts b/tests/service.test.ts index 77915ca..7842384 100644 --- a/tests/service.test.ts +++ b/tests/service.test.ts @@ -2,7 +2,7 @@ import type { ITestCaseHookParameter } from '@cucumber/cucumber' import { TestStepResultStatus } from '@cucumber/messages' import { describe, expect, it } from '@jest/globals' import minimist from 'minimist' -import { readFile, rm } from 'node:fs/promises' +import { mkdir, readdir, readFile, rm, writeFile } from 'node:fs/promises' import { tmpdir } from 'node:os' import { join } from 'node:path' import { argv, platform } from 'node:process' @@ -131,6 +131,22 @@ describe('wdio-rerun-service', () => { expect(service.commandPrefix).toEqual('') expect(service.customParameters).toEqual('--foobar') }) + + it('can configure allowMultipleReruns', async () => { + const service = new RerunService({ + allowMultipleReruns: true, + }) + await expect( + service.before({}, ['features/sample.feature']), + ).resolves.toBeUndefined() + expect(service.ignoredTags).toEqual([]) + expect(service.rerunDataDir).toEqual('./results/rerun') + expect(service.rerunScriptPath).toEqual(rerunScriptFile) + expect(service.commandPrefix).toEqual('') + expect(service.customParameters).toEqual('') + expect(service.disabled).toEqual(false) + expect(service.allowMultipleReruns).toEqual(true) + }) }) describe('before', () => { @@ -144,6 +160,33 @@ describe('wdio-rerun-service', () => { const service = new RerunService() await expect(service.before({}, [])).resolves.toBeUndefined() }) + + it('should clear the rerun directory when multiple reruns are allowed', async () => { + await mkdir('./results/rerun', { recursive: true }) + await writeFile('./results/rerun/1.txt', 'test') + const service = new RerunService({ allowMultipleReruns: true }) + await service.before({}, specFile) + const filesInDir = await readdir('./results/rerun') + expect(filesInDir).toHaveLength(0) + }) + + it('should not clear the rerun directory when multiple reruns are not allowed', async () => { + await mkdir('./results/rerun', { recursive: true }) + await writeFile('./results/rerun/1.txt', 'test') + const service = new RerunService({ allowMultipleReruns: false }) + await service.before({}, specFile) + const filesInDir = await readdir('./results/rerun') + expect(filesInDir).toHaveLength(1) + }) + + it('should not clear the rerun directory when rerun is disabled', async () => { + await mkdir('./results/rerun', { recursive: true }) + await writeFile('./results/rerun/1.txt', 'test') + const service = new RerunService() + await service.before({}, specFile) + const filesInDir = await readdir('./results/rerun') + expect(filesInDir).toHaveLength(1) + }) }) describe('afterScenario', () => { @@ -388,5 +431,31 @@ describe('wdio-rerun-service', () => { expect(err?.code).toBe('ENOENT') expect(rerunScript).toBeUndefined() }) + + it('should add failed specs to rerun script if DISABLE_RERUN is set to false', async () => { + process.env['DISABLE_RERUN'] = 'false' + const rerunDataDir = join(tmpdir(), 'rerun-data') + const rerunScriptPath = join(rerunDataDir, rerunScriptFile) + const service = new RerunService({ + rerunDataDir, + rerunScriptPath, + allowMultipleReruns: true, + }) + await service.before({}, []) + service.nonPassingItems = nonPassingItemsMocha + await service.after() + await service.onComplete() + const disableRerun = + platform === 'win32' + ? 'set DISABLE_RERUN=false &&' + : 'DISABLE_RERUN=false' + const rerunScript = await readFile(rerunScriptPath, 'utf8') + const parsedArgs = minimist(argv.slice(2)) + const args = parsedArgs._[0] ?? '' + expect(rerunScript).toBe( + `${disableRerun} npx wdio ${args} --spec=tests/sample1.test.ts --spec=tests/sample2.test.ts`, + ) + await rm(rerunDataDir, { recursive: true, force: true }) + }) }) })