Skip to content

Commit 5f3630b

Browse files
Fix macOS test flakiness (#14869)
1 parent 894bf9f commit 5f3630b

File tree

3 files changed

+46
-18
lines changed

3 files changed

+46
-18
lines changed

integrations/utils.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -214,8 +214,9 @@ export function test(
214214
})
215215

216216
options.onTestFailed(() => {
217-
// In debug mode, messages are logged to the console immediately
218-
if (debug) return
217+
// In only or debug mode, messages are logged to the console
218+
// immediately.
219+
if (only || debug) return
219220

220221
for (let [type, message] of combined) {
221222
if (type === 'stdout') {
@@ -293,7 +294,7 @@ export function test(
293294

294295
let dir = path.dirname(full)
295296
await fs.mkdir(dir, { recursive: true })
296-
await fs.writeFile(full, content)
297+
await fs.writeFile(full, content, 'utf-8')
297298
},
298299

299300
async create(filenames: string[]): Promise<void> {

packages/@tailwindcss-cli/src/commands/build/index.ts

Lines changed: 40 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -203,9 +203,6 @@ export async function handle(args: Result<ReturnType<typeof options>>) {
203203

204204
// Scan the entire `base` directory for full rebuilds.
205205
if (rebuildStrategy === 'full') {
206-
// Clear all watchers
207-
cleanupWatchers()
208-
209206
// Read the new `input`.
210207
let input = args['--input']
211208
? args['--input'] === '-'
@@ -226,7 +223,12 @@ export async function handle(args: Result<ReturnType<typeof options>>) {
226223
env.DEBUG && console.timeEnd('[@tailwindcss/cli] Scan for candidates')
227224

228225
// Setup new watchers
229-
cleanupWatchers = await createWatchers(watchDirectories(scanner), handle)
226+
let newCleanupWatchers = await createWatchers(watchDirectories(scanner), handle)
227+
228+
// Clear old watchers
229+
await cleanupWatchers()
230+
231+
cleanupWatchers = newCleanupWatchers
230232

231233
// Re-compile the CSS
232234
env.DEBUG && console.time('[@tailwindcss/cli] Build CSS')
@@ -271,8 +273,10 @@ export async function handle(args: Result<ReturnType<typeof options>>) {
271273
// disable this behavior with `--watch=always`.
272274
if (args['--watch'] !== 'always') {
273275
process.stdin.on('end', () => {
274-
cleanupWatchers()
275-
process.exit(0)
276+
cleanupWatchers().then(
277+
() => process.exit(0),
278+
() => process.exit(1),
279+
)
276280
})
277281
}
278282

@@ -307,6 +311,29 @@ function watchDirectories(scanner: Scanner) {
307311
}
308312

309313
async function createWatchers(dirs: string[], cb: (files: string[]) => void) {
314+
// Remove any directories that are children of an already watched directory.
315+
// If we don't we may not get notified of certain filesystem events regardless
316+
// of whether or not they are for the directory that is duplicated.
317+
318+
// 1. Sort in asc by length
319+
dirs = dirs.sort((a, z) => a.length - z.length)
320+
321+
// 2. Remove any directories that are children of another directory
322+
let toRemove = []
323+
324+
// /project-a 0
325+
// /project-a/src 1
326+
327+
for (let i = 0; i < dirs.length; ++i) {
328+
for (let j = 0; j < i; ++j) {
329+
if (!dirs[i].startsWith(`${dirs[j]}/`)) continue
330+
331+
toRemove.push(dirs[i])
332+
}
333+
}
334+
335+
dirs = dirs.filter((dir) => !toRemove.includes(dir))
336+
310337
// Track all Parcel watchers for each glob.
311338
//
312339
// When we encounter a change in a CSS file, we need to setup new watchers and
@@ -322,9 +349,9 @@ async function createWatchers(dirs: string[], cb: (files: string[]) => void) {
322349
// A changed file can be watched by multiple watchers, but we only want to
323350
// handle the file once. We debounce the handle function with the collected
324351
// files to handle them in a single batch and to avoid multiple rebuilds.
325-
function enqueueCallback() {
326-
// Dispose all existing macrotask.
327-
debounceQueue.dispose()
352+
async function enqueueCallback() {
353+
// Dispose all existing macrotasks.
354+
await debounceQueue.dispose()
328355

329356
// Setup a new macrotask to handle the files in batch.
330357
debounceQueue.queueMacrotask(() => {
@@ -365,17 +392,17 @@ async function createWatchers(dirs: string[], cb: (files: string[]) => void) {
365392
)
366393

367394
// Handle the tracked files at some point in the future.
368-
enqueueCallback()
395+
await enqueueCallback()
369396
})
370397

371398
// Ensure we cleanup the watcher when we're done.
372399
watchers.add(unsubscribe)
373400
}
374401

375402
// Cleanup
376-
return () => {
377-
watchers.dispose()
378-
debounceQueue.dispose()
403+
return async () => {
404+
await watchers.dispose()
405+
await debounceQueue.dispose()
379406
}
380407
}
381408

packages/@tailwindcss-cli/src/utils/disposables.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,9 @@ export class Disposables {
3535
/**
3636
* Dispose all disposables at once.
3737
*/
38-
dispose() {
38+
async dispose() {
3939
for (let dispose of this.#disposables) {
40-
dispose()
40+
await dispose()
4141
}
4242

4343
this.#disposables.clear()

0 commit comments

Comments
 (0)