Skip to content

Commit

Permalink
fix: search parent folders for split file (#157)
Browse files Browse the repository at this point in the history
* feat: search parent folders for split file

* add find timings test to CI

* set the custom spec pattern
  • Loading branch information
bahmutov committed Nov 8, 2023
1 parent e484f4c commit a8bd26b
Show file tree
Hide file tree
Showing 9 changed files with 120 additions and 5 deletions.
18 changes: 18 additions & 0 deletions .github/workflows/ci.yml
Expand Up @@ -173,6 +173,23 @@ jobs:
with:
command: npm run timings-no-file

test-find-timings-file:
runs-on: ubuntu-22.04
steps:
- name: Checkout 🛎
uses: actions/checkout@v4
- name: Needs to find the timings file 🧪
# https://github.com/cypress-io/github-action
uses: cypress-io/github-action@v5
with:
project: examples/timings-file/tests/cypress-tests
env:
SPLIT: 1
SPLIT_INDEX: 0
# the timings file is not next to the config file
# but in the project folder
SPLIT_FILE: timings.json

test-workflow-e2e:
# https://github.com/bahmutov/cypress-workflows
uses: bahmutov/cypress-workflows/.github/workflows/split.yml@v1
Expand Down Expand Up @@ -220,6 +237,7 @@ jobs:
test-timings,
test-timings-no-file,
test-merge-timings,
test-find-timings-file,
]
runs-on: ubuntu-22.04
steps:
Expand Down
2 changes: 2 additions & 0 deletions README.md
Expand Up @@ -268,6 +268,8 @@ If the timings file does not exist yet, the timings will be written into the fil

See example [bahmutov/cypress-split-timings-example](https://github.com/bahmutov/cypress-split-timings-example).

**Note 2:** during Cypress execution, the working directory is set to the folder with the Cypress config file. This module tries its best to find the split file by searching the parent folders to the Git repo or root folder.

## Merging timings files

This module includes a bin utility to merge multiple timings files into one. Example:
Expand Down
17 changes: 17 additions & 0 deletions examples/timings-file/tests/cypress-tests/cypress.config.js
@@ -0,0 +1,17 @@
const { defineConfig } = require('cypress')
const cypressSplit = require('../../../../src')

module.exports = defineConfig({
e2e: {
// baseUrl, etc
supportFile: false,
fixturesFolder: false,
specPattern: 'e2e/*.cy.js',
setupNodeEvents(on, config) {
console.log('cwd is', process.cwd())
cypressSplit(on, config)
// IMPORTANT: return the config object
return config
},
},
})
1 change: 1 addition & 0 deletions examples/timings-file/tests/cypress-tests/e2e/spec-a.cy.js
@@ -0,0 +1 @@
it('works A', () => {})
1 change: 1 addition & 0 deletions examples/timings-file/tests/cypress-tests/e2e/spec-b.cy.js
@@ -0,0 +1 @@
it('works B', () => {})
1 change: 1 addition & 0 deletions examples/timings-file/tests/cypress-tests/e2e/spec-c.cy.js
@@ -0,0 +1 @@
it('works C', () => {})
16 changes: 16 additions & 0 deletions examples/timings-file/timings.json
@@ -0,0 +1,16 @@
{
"durations": [
{
"spec": "cypress/e2e/spec-a.cy.js",
"duration": 100
},
{
"spec": "cypress/e2e/spec-b.cy.js",
"duration": 100
},
{
"spec": "cypress/e2e/spec-c.cy.js",
"duration": 1000
}
]
}
50 changes: 50 additions & 0 deletions src/find-file.js
@@ -0,0 +1,50 @@
// @ts-check

const debug = require('debug')('cypress-split')
const exists = require('fs').existsSync
const { join, normalize } = require('path')

function isGitRootFolder(folder) {
const gitRoot = '.git'
const full = join(folder, gitRoot)
return exists(full)
}

/**
* Finds the file using the current working directory or its parent
* directories up to the Git root folder.
* @param {string} filename File to find
* @returns {string|undefined} found file path or undefined
*/
function findFile(filename) {
if (!filename) {
throw new Error('Missing the filename')
}

let currentFolder = process.cwd()
let found

while (true) {
const maybePath = join(currentFolder, filename)
if (exists(maybePath)) {
found = maybePath
debug('found file %s', found)
break
}
if (isGitRootFolder(currentFolder)) {
debug('reached git root folder %s', currentFolder)
debug('but could not find %s', filename)
break
}
const parent = normalize(join(currentFolder, '..'))
if (parent === currentFolder) {
debug('reached top level folder %s', currentFolder)
debug('but could not find tool %s', filename)
break
}
currentFolder = parent
}
return found
}

module.exports = { findFile }
19 changes: 14 additions & 5 deletions src/index.js
Expand Up @@ -5,6 +5,7 @@ const debug = require('debug')('cypress-split')
const { getSpecs } = require('find-cypress-specs')
const ghCore = require('@actions/core')
const { getChunk } = require('./chunk')
const { findFile } = require('./find-file')
const {
splitByDuration,
hasTimeDifferences,
Expand Down Expand Up @@ -172,10 +173,17 @@ function cypressSplit(on, config) {
const cwd = process.cwd()
console.log('%s specs from the current directory %s', label, cwd)

let foundSplitFile
if (SPLIT_FILE) {
debug('loading split file %s', SPLIT_FILE)
try {
const splitFile = JSON.parse(fs.readFileSync(SPLIT_FILE, 'utf8'))
foundSplitFile = findFile(SPLIT_FILE)
if (!foundSplitFile) {
throw new Error(
`Could not find ${SPLIT_FILE} based on the current working directory ${cwd}`,
)
}
const splitFile = JSON.parse(fs.readFileSync(foundSplitFile, 'utf8'))
const previousDurations = splitFile.durations
const averageDuration =
previousDurations
Expand Down Expand Up @@ -309,11 +317,11 @@ function cypressSplit(on, config) {
const timingsString = JSON.stringify(timings, null, 2)
console.log(timingsString)

if (!fs.existsSync(SPLIT_FILE)) {
if (!foundSplitFile) {
console.log('%s writing out timings file %s', label, SPLIT_FILE)
fs.writeFileSync(SPLIT_FILE, timingsString + '\n', 'utf8')
} else {
const splitFile = JSON.parse(fs.readFileSync(SPLIT_FILE, 'utf8'))
const splitFile = JSON.parse(fs.readFileSync(foundSplitFile, 'utf8'))
const hasUpdatedTimings = hasTimeDifferences(splitFile, timings, 0.1)
if (hasUpdatedTimings) {
// TODO: merge split file with new timings
Expand All @@ -328,10 +336,11 @@ function cypressSplit(on, config) {
debug('previous timings has %d entries', splitFile.durations.length)
debug('current timings has %d entries', timings.durations.length)
debug(
'merged timings has %d entries',
'merged timings has %d entries written to %s',
mergedTimings.durations.length,
foundSplitFile,
)
fs.writeFileSync(SPLIT_FILE, mergedText + '\n', 'utf8')
fs.writeFileSync(foundSplitFile, mergedText + '\n', 'utf8')
} else {
console.log('%s spec timings unchanged', label)
}
Expand Down

0 comments on commit a8bd26b

Please sign in to comment.