mirror of
https://github.com/tailwindlabs/tailwindcss.git
synced 2025-12-08 21:36:08 +00:00
* add integration test tools * setup jest in the integrations folder * add `test:integrations` script The default `npm test` script will ignore all the tests in the `integrations` folder. * add integration tests with `webpack 5` * add integration tests with `postcss-cli` * add `npm run install:integrations` script This script will run `npm install` in every integration, and in the integrations folder itself (to setup Jest for example). * add `toIncludeCss` custom matcher * increate Jest timeout for integration tests * add integration tests with `vite` * add integration tests with `webpack 4` * add isomorphic fetch * add the ability to wait for specific stdout/stderr output * write vite tests, assert using API calls We will wait for the correct stdout/stderr output, once we know that we can request the fresh css, we will fetch it and make assertions accordingly. Port is currently hardcoded, maybe we should use a packaage to ensure that we use a free port. * add integration tests with `rollup` * add integration tests with `parcel` * run all integration tests in band * add .gitignore in integrations folder
140 lines
4.0 KiB
JavaScript
140 lines
4.0 KiB
JavaScript
let { rm, existsSync } = require('fs')
|
|
let path = require('path')
|
|
let fs = require('fs/promises')
|
|
|
|
let chokidar = require('chokidar')
|
|
|
|
let resolveToolRoot = require('./resolve-tool-root')
|
|
|
|
module.exports = function ({
|
|
/** Output directory, relative to the tool. */
|
|
output = 'dist',
|
|
|
|
/** Input directory, relative to the tool. */
|
|
input = 'src',
|
|
|
|
/** Whether or not you want to cleanup the output directory. */
|
|
cleanup = true,
|
|
} = {}) {
|
|
let toolRoot = resolveToolRoot()
|
|
let fileCache = {}
|
|
|
|
let absoluteOutputFolder = path.resolve(toolRoot, output)
|
|
let absoluteInputFolder = path.resolve(toolRoot, input)
|
|
|
|
if (cleanup) {
|
|
beforeAll((done) => rm(absoluteOutputFolder, { recursive: true, force: true }, done))
|
|
afterEach((done) => rm(absoluteOutputFolder, { recursive: true, force: true }, done))
|
|
}
|
|
|
|
// Restore all written files
|
|
afterEach(async () => {
|
|
await Promise.all(
|
|
Object.entries(fileCache).map(([file, content]) => fs.writeFile(file, content, 'utf8'))
|
|
)
|
|
})
|
|
|
|
async function readdir(start, parent = []) {
|
|
let files = await fs.readdir(start, { withFileTypes: true })
|
|
let resolvedFiles = await Promise.all(
|
|
files.map((file) => {
|
|
if (file.isDirectory()) {
|
|
return readdir(path.resolve(start, file.name), [...parent, file.name])
|
|
}
|
|
return parent.concat(file.name).join(path.sep)
|
|
})
|
|
)
|
|
return resolvedFiles.flat(Infinity)
|
|
}
|
|
|
|
async function resolveFile(fileOrRegex, directory) {
|
|
if (fileOrRegex instanceof RegExp) {
|
|
let files = await readdir(directory)
|
|
if (files.length === 0) {
|
|
throw new Error(`No files exists in "${directory}"`)
|
|
}
|
|
|
|
let filtered = files.filter((file) => fileOrRegex.test(file))
|
|
if (filtered.length === 0) {
|
|
throw new Error(`Not a single file matched: ${fileOrRegex}`)
|
|
} else if (filtered.length > 1) {
|
|
throw new Error(`Multiple files matched: ${fileOrRegex}`)
|
|
}
|
|
|
|
return filtered[0]
|
|
}
|
|
|
|
return fileOrRegex
|
|
}
|
|
|
|
return {
|
|
async readOutputFile(file) {
|
|
file = await resolveFile(file, absoluteOutputFolder)
|
|
return fs.readFile(path.resolve(absoluteOutputFolder, file), 'utf8')
|
|
},
|
|
async appendToInputFile(file, contents) {
|
|
let filePath = path.resolve(absoluteInputFolder, file)
|
|
if (!fileCache[filePath]) {
|
|
fileCache[filePath] = await fs.readFile(filePath, 'utf8')
|
|
}
|
|
|
|
return fs.appendFile(filePath, contents, 'utf8')
|
|
},
|
|
async writeInputFile(file, contents) {
|
|
let filePath = path.resolve(absoluteInputFolder, file)
|
|
if (!fileCache[filePath]) {
|
|
fileCache[filePath] = await fs.readFile(filePath, 'utf8')
|
|
}
|
|
|
|
return fs.writeFile(path.resolve(absoluteInputFolder, file), contents, 'utf8')
|
|
},
|
|
async waitForOutputFileCreation(file) {
|
|
if (file instanceof RegExp) {
|
|
let r = file
|
|
let watcher = chokidar.watch(absoluteOutputFolder)
|
|
|
|
return new Promise((resolve) => {
|
|
watcher.on('add', (file) => {
|
|
if (r.test(file)) {
|
|
watcher.close()
|
|
resolve()
|
|
}
|
|
})
|
|
})
|
|
} else {
|
|
let filePath = path.resolve(absoluteOutputFolder, file)
|
|
let watcher = chokidar.watch(filePath)
|
|
|
|
let watcherPromise = new Promise((resolve) => {
|
|
watcher.once('add', () => {
|
|
watcher.close()
|
|
resolve()
|
|
})
|
|
})
|
|
|
|
if (existsSync(filePath)) {
|
|
watcher.close()
|
|
return Promise.resolve()
|
|
}
|
|
|
|
return watcherPromise
|
|
}
|
|
},
|
|
async waitForOutputFileChange(file, cb = () => {}) {
|
|
file = await resolveFile(file, absoluteOutputFolder)
|
|
|
|
let filePath = path.resolve(absoluteOutputFolder, file)
|
|
let watcher = chokidar.watch(filePath)
|
|
|
|
return new Promise((resolve) => {
|
|
let chain = Promise.resolve()
|
|
watcher.once('change', () => {
|
|
watcher.close()
|
|
chain.then(() => resolve())
|
|
})
|
|
chain.then(() => cb())
|
|
})
|
|
},
|
|
}
|
|
}
|