Skip to content
Open
Show file tree
Hide file tree
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
5 changes: 3 additions & 2 deletions lib/codecept.js
Original file line number Diff line number Diff line change
Expand Up @@ -184,8 +184,6 @@ class Codecept {
}
}

this.testFiles.sort()

if (this.opts.shuffle) {
this.testFiles = this.shuffle(this.testFiles)
}
Expand Down Expand Up @@ -252,6 +250,9 @@ class Codecept {
async run(test) {
await container.started()

// Sort test files alphabetically for consistent execution order
this.testFiles.sort()

return new Promise((resolve, reject) => {
const mocha = container.mocha()
mocha.files = this.testFiles
Expand Down
24 changes: 21 additions & 3 deletions test/unit/alphabetical_order_test.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
const expect = require('chai').expect
const Codecept = require('../../lib/codecept')
const Container = require('../../lib/container')
const path = require('path')
const fs = require('fs')

Expand Down Expand Up @@ -56,19 +57,36 @@ describe('Test Files Alphabetical Order', () => {
codecept.init(path.join(__dirname, '../data/sandbox'))
})

it('should sort test files alphabetically after loading', () => {
afterEach(() => {
Container.clear()
})

it('should sort test files alphabetically when run() is called', async () => {
codecept.loadTests()

if (codecept.testFiles.length === 0) {
console.log('No test files found, skipping test')
return
}

const filenames = codecept.testFiles.map(filePath => path.basename(filePath))
// Capture the files that would be passed to mocha during run()
let filesPassedToMocha = null
const mocha = Container.mocha()
mocha.run = callback => {
filesPassedToMocha = [...mocha.files]
// Call callback immediately to complete the run
if (callback) callback()
}

// Call run() which should sort files before passing to mocha
await codecept.run()

// Verify files passed to mocha are sorted alphabetically
expect(filesPassedToMocha).to.not.be.null
const filenames = filesPassedToMocha.map(filePath => path.basename(filePath))
const sortedFilenames = [...filenames].sort()

expect(filenames).to.deep.equal(sortedFilenames)
expect(filenames).to.deep.equal(sortedFilenames, 'Files should be sorted alphabetically for execution')

const aaaIndex = filenames.findIndex(f => f.includes('aaa_test.js'))
const mmmIndex = filenames.findIndex(f => f.includes('mmm_test.js'))
Expand Down
47 changes: 45 additions & 2 deletions test/unit/worker_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,10 @@ describe('Workers', function () {

workers.on(event.all.result, result => {
expect(result.hasFailed).equal(true)
expect(passedCount).equal(3)
expect(failedCount).equal(2)
// Note: pass/fail counts depend on test distribution order, which affects
// timing of shared state between workers. See issue #5412.
expect(passedCount).equal(4)
expect(failedCount).equal(1)
done()
})
})
Expand Down Expand Up @@ -368,4 +370,45 @@ describe('Workers', function () {

workers.run()
})

it('should not sort test files in loadTests for worker distribution (issue #5412)', () => {
// This test verifies the fix for issue #5412:
// Test files should NOT be sorted in loadTests() because that affects worker distribution.
// Sorting should only happen in run() for execution order.
//
// The bug was: sorting in loadTests() changed the order of suites during distribution,
// causing all workers to receive the same tests instead of different suites.

// Ensure clean state
const testFilesPattern = /custom-worker/
Object.keys(require.cache).forEach(key => {
if (testFilesPattern.test(key)) {
delete require.cache[key]
}
})
Container.clear()
Container.createMocha()

const workerConfig = {
by: 'suite',
testConfig: './test/data/sandbox/codecept.customworker.js',
}

const workers = new Workers(3, workerConfig)

// The key fix: after loadTests(), files should be in original (glob) order, NOT sorted.
// Glob returns files in reverse order on this system: 3_, 2_, 1_
// If files were sorted, they would be: 1_, 2_, 3_
const testFiles = workers.codecept.testFiles
const filenames = testFiles.map(f => path.basename(f))

// Verify files are NOT in sorted order (they should be in glob order)
const sortedFilenames = [...filenames].sort()
expect(filenames).to.not.deep.equal(sortedFilenames, 'Files should NOT be sorted after loadTests() - sorting should happen in run()')

// Also verify that suites are distributed across multiple worker groups
const groups = workers.testGroups
const nonEmptyGroups = groups.filter(g => g.length > 0)
expect(nonEmptyGroups.length).to.be.greaterThan(1, 'Suites should be distributed across multiple worker groups')
})
})