We have a beefy server in our CI and we want to take advantage of it and parallelize our cypress test suite on the same machine. We know that cypress doesn't encourage it but it should be possible!
We have a bash script that splits all of the test files in n
groups and runs cypress on each group on a new port in the background with:
npx cypress run --spec $specFiles --port $port --headless &
In principle, this should work as each process will run its files on a separate headless browser. However, with >4 workers, we get all sort of errors:
- Custom commands not found
- Tests that pass on a single worker now fail non-deterministically:
- Syntax errors?!? (code runs correctly on a single worker)
- Timeouts - these shouldn't happen since the webserver is not under any significant load!
We are trying our best to avoid running each cypress instance as a new docker container to avoid the additional CI complexity but will dive into that if necessary. Are we missing something obvious here?
Here is the complete script for reference:
#!/bin/bash
nThreads=3
print_usage() {
printf "Usage:
./run_tests_parallel.sh -n <number of threads to use>
Defaults to $nThreads threads\n"
exit 0;
}
while true; do
case "$1" in
-n | --threads ) nThreads=$2; shift 2 ;;
-h | --help ) print_usage ; shift ;;
-- ) shift; break ;;
* ) break ;;
esac
done
echo Using $nThreads threads
# Return non-zero if any of the subprocesses
# returns non-zero
set -eu
testFiles=`find . -name "*.test.ts" -not -path "./node_modules/*"`
# init testF
testFilesPerThread=()
for (( n=0; n<$nThreads; n++ )); do
testFilesPerThread+=("")
done
i=0
for testFile in $testFiles; do
testFilesPerThread[$i]="${testFilesPerThread[$i]} $testFile"
i=$((($i + 1)%$nThreads))
done
pids=()
for (( i=0; i<${#testFilesPerThread[@]}; i++ )); do
echo Thread $i has files: ${testFilesPerThread[$i]}
# strip string and join files with ","
specFiles=`echo ${testFilesPerThread[$i]} | xargs | tr -s "\ " ","`
port=$((30001+$i))
# run tests in background
npx cypress run --spec $specFiles --port $port --headless &
pids+=($!)
echo "Spawned PID ${pids[${#pids[@]}-1]} for thread $i on port $port"
done
for pid in ${pids[@]} ; do
echo "Waiting for PID $pid."
wait $pid
done
echo DONE.