From a8bd26b6915ab68fe706db224119304ce19ca15f Mon Sep 17 00:00:00 2001 From: Gleb Bahmutov Date: Wed, 8 Nov 2023 09:13:23 -0500 Subject: [PATCH] fix: search parent folders for split file (#157) * feat: search parent folders for split file * add find timings test to CI * set the custom spec pattern --- .github/workflows/ci.yml | 18 +++++++ README.md | 2 + .../tests/cypress-tests/cypress.config.js | 17 +++++++ .../tests/cypress-tests/e2e/spec-a.cy.js | 1 + .../tests/cypress-tests/e2e/spec-b.cy.js | 1 + .../tests/cypress-tests/e2e/spec-c.cy.js | 1 + examples/timings-file/timings.json | 16 ++++++ src/find-file.js | 50 +++++++++++++++++++ src/index.js | 19 +++++-- 9 files changed, 120 insertions(+), 5 deletions(-) create mode 100644 examples/timings-file/tests/cypress-tests/cypress.config.js create mode 100644 examples/timings-file/tests/cypress-tests/e2e/spec-a.cy.js create mode 100644 examples/timings-file/tests/cypress-tests/e2e/spec-b.cy.js create mode 100644 examples/timings-file/tests/cypress-tests/e2e/spec-c.cy.js create mode 100644 examples/timings-file/timings.json create mode 100644 src/find-file.js diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 817bcf1..4f9ceae 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -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 @@ -220,6 +237,7 @@ jobs: test-timings, test-timings-no-file, test-merge-timings, + test-find-timings-file, ] runs-on: ubuntu-22.04 steps: diff --git a/README.md b/README.md index b6b2471..428430f 100644 --- a/README.md +++ b/README.md @@ -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: diff --git a/examples/timings-file/tests/cypress-tests/cypress.config.js b/examples/timings-file/tests/cypress-tests/cypress.config.js new file mode 100644 index 0000000..a0e6d07 --- /dev/null +++ b/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 + }, + }, +}) diff --git a/examples/timings-file/tests/cypress-tests/e2e/spec-a.cy.js b/examples/timings-file/tests/cypress-tests/e2e/spec-a.cy.js new file mode 100644 index 0000000..73a0af8 --- /dev/null +++ b/examples/timings-file/tests/cypress-tests/e2e/spec-a.cy.js @@ -0,0 +1 @@ +it('works A', () => {}) diff --git a/examples/timings-file/tests/cypress-tests/e2e/spec-b.cy.js b/examples/timings-file/tests/cypress-tests/e2e/spec-b.cy.js new file mode 100644 index 0000000..3261a0c --- /dev/null +++ b/examples/timings-file/tests/cypress-tests/e2e/spec-b.cy.js @@ -0,0 +1 @@ +it('works B', () => {}) diff --git a/examples/timings-file/tests/cypress-tests/e2e/spec-c.cy.js b/examples/timings-file/tests/cypress-tests/e2e/spec-c.cy.js new file mode 100644 index 0000000..037e647 --- /dev/null +++ b/examples/timings-file/tests/cypress-tests/e2e/spec-c.cy.js @@ -0,0 +1 @@ +it('works C', () => {}) diff --git a/examples/timings-file/timings.json b/examples/timings-file/timings.json new file mode 100644 index 0000000..d39f427 --- /dev/null +++ b/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 + } + ] +} diff --git a/src/find-file.js b/src/find-file.js new file mode 100644 index 0000000..98ae301 --- /dev/null +++ b/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 } diff --git a/src/index.js b/src/index.js index 4ffbe7c..7ec3103 100644 --- a/src/index.js +++ b/src/index.js @@ -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, @@ -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 @@ -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 @@ -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) }