Skip to content

Commit

Permalink
feat(testing): custom preprocessor
Browse files Browse the repository at this point in the history
  • Loading branch information
mandarini committed Dec 1, 2022
1 parent 455c5cb commit 6b6577a
Show file tree
Hide file tree
Showing 9 changed files with 147 additions and 28 deletions.
2 changes: 1 addition & 1 deletion docs/generated/packages/cypress.json
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@
"bundler": {
"description": "The Cypress builder to use.",
"type": "string",
"enum": ["vite", "webpack"],
"enum": ["vite", "webpack", "none"],
"x-prompt": "Which Cypress builder do you want to use?",
"default": "webpack"
}
Expand Down
29 changes: 27 additions & 2 deletions packages/cypress/plugins/cypress-preset.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ import {
createProjectRootMappings,
findProjectForPath,
} from 'nx/src/project-graph/utils/find-project-for-path';
import path = require('path');
import vitePreprocessor from '../src/plugins/preprocessor-vite';

interface BaseCypressPreset {
videosFolder: string;
Expand Down Expand Up @@ -72,14 +74,37 @@ export function nxBaseCypressPreset(pathToConfig: string): BaseCypressPreset {
*
* @param pathToConfig will be used to construct the output paths for videos and screenshots
*/
export function nxE2EPreset(pathToConfig: string) {
return {
export function nxE2EPreset(
pathToConfig: string,
options?: { vite: { viteConfigPath: string } }
) {
const baseConfig = {
...nxBaseCypressPreset(pathToConfig),
fileServerFolder: '.',
supportFile: 'src/support/e2e.ts',
specPattern: 'src/**/*.cy.{js,jsx,ts,tsx}',
fixturesFolder: 'src/fixtures',
};

/**
* - Not necessary to have the path to vite config
* - vite.config if it exists it can be cypress-project specific
* - generate without path to vite-config, add in docs how user can provide it
* - add in the docs how to set up custom/more setupNodeEvents
*/

if (options.vite?.viteConfigPath) {
return {
...baseConfig,
setupNodeEvents(on) {
on(
'file:preprocessor',
vitePreprocessor(`${options.vite?.viteConfigPath}`)
);
},
};
}
return baseConfig;
}

export function getProjectConfigByPath(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ import {
toJS,
Tree,
updateJson,
workspaceRoot,
} from '@nrwl/devkit';
import { Linter, lintProjectGenerator } from '@nrwl/linter';
import { runTasksInSerial } from '@nrwl/workspace/src/utilities/run-tasks-in-serial';
Expand Down Expand Up @@ -57,7 +56,7 @@ function createFiles(tree: Tree, options: CypressProjectSchema) {
// We cannot assume the file name
const projectViteConfigFile = getViteConfigFileFullPath(
tree,
options.projectName,
options.projectName.replace(`-e2e`, ``),
options.projectRoot
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,11 @@ import { defineConfig } from 'cypress';
import { nxE2EPreset } from '@nrwl/cypress/plugins/cypress-preset';

export default defineConfig({
<% if (bundler !== 'vite'){ %>
e2e: nxE2EPreset(__dirname)
<% } %>
<% if (bundler === 'vite'){ %>
e2e: {
...nxE2EPreset(__dirname),
setupNodeEvents(on) {
on(
'file:preprocessor',
vitePreprocessor(path.resolve(__dirname, '<%= offsetFromRoot %><%= projectViteConfigFile %>'))
);
},
e2e: nxE2EPreset(__dirname<% if (bundler === 'vite'){ %>,
{
vite: {
viteConfigPath: '<%= cypressProjectSpecificViteConfigPath %>'
}
}
<% } %>
<% } %>)
});
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,5 @@ export interface Schema {
standaloneConfig?: boolean;
skipPackageJson?: boolean;
rootProject?: boolean;
bundler?: 'webpack' | 'vite';
bundler?: 'webpack' | 'vite' | 'none';
}
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@
"bundler": {
"description": "The Cypress builder to use.",
"type": "string",
"enum": ["vite", "webpack"],
"enum": ["vite", "webpack", "none"],
"x-prompt": "Which Cypress builder do you want to use?",
"default": "webpack"
}
Expand Down
89 changes: 89 additions & 0 deletions packages/cypress/src/plugins/preprocessor-vite.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
// copied from https://github.com/mammadataei/cypress-vite

import * as path from 'path';
import { build, InlineConfig } from 'vite';
import type { RollupOutput, RollupWatcher, WatcherOptions } from 'rollup';

type CypressPreprocessor = (
file: Record<string, any>
) => string | Promise<string>;

/**
* Cypress preprocessor for running e2e tests using vite.
*
* @param {string} userConfigPath
* @example
* setupNodeEvents(on) {
* on(
* 'file:preprocessor',
* vitePreprocessor(path.resolve(__dirname, './vite.config.ts')),
* )
* },
*/
function vitePreprocessor(userConfigPath?: string): CypressPreprocessor {
return async (file) => {
const { outputPath, filePath, shouldWatch } = file;

const fileName = path.basename(outputPath);
const filenameWithoutExtension = path.basename(
outputPath,
path.extname(outputPath)
);

const defaultConfig: InlineConfig = {
logLevel: 'silent',
define: {
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV),
},
build: {
emptyOutDir: false,
minify: false,
outDir: path.dirname(outputPath),
sourcemap: true,
write: true,
watch: getWatcherConfig(shouldWatch),
lib: {
entry: filePath,
fileName: () => fileName,
formats: ['umd'],
name: filenameWithoutExtension,
},
},
};

const watcher = await build({
configFile: userConfigPath,
...defaultConfig,
});

if (shouldWatch && isWatcher(watcher)) {
watcher.on('event', (event) => {
if (event.code === 'END') {
file.emit('rerun');
}

if (event.code === 'ERROR') {
console.error(event);
}
});

file.on('close', () => {
watcher.close();
});
}

return outputPath;
};
}

function getWatcherConfig(shouldWatch: boolean): WatcherOptions | null {
return shouldWatch ? {} : null;
}

type BuildResult = RollupWatcher | RollupOutput | RollupOutput[];

function isWatcher(watcher: BuildResult): watcher is RollupWatcher {
return (watcher as RollupWatcher).on !== undefined;
}

export default vitePreprocessor;
5 changes: 3 additions & 2 deletions packages/vite/src/utils/generator-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -475,10 +475,11 @@ export function getViteConfigFileFullPath(
return normalizeConfigFilePath(
projectViteConfigFileName,
workspaceRoot,
projectConfig.root
projectConfig.root,
tree
);
} else if (projectRoot) {
return normalizeConfigFilePath(undefined, workspaceRoot, projectRoot);
return normalizeConfigFilePath(undefined, workspaceRoot, projectRoot, tree);
}
return undefined;
}
24 changes: 18 additions & 6 deletions packages/vite/src/utils/options-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
logger,
parseTargetString,
readTargetOptions,
Tree,
} from '@nrwl/devkit';
import { existsSync } from 'fs';
import { join, relative } from 'path';
Expand Down Expand Up @@ -44,17 +45,28 @@ export async function getBuildAndSharedConfig(
} as InlineConfig);
}

// I understand that this may seem like an overkill,
// but since we're giving the user the option to set their own vite config
// file, we need to make sure that we're referencing the correct file.
// We cannot assume the file name
export function normalizeConfigFilePath(
configFile: string,
workspaceRoot: string,
projectRoot: string
projectRoot: string,
tree?: Tree
): string {
const customViteFilePath = joinPathFragments(
`${workspaceRoot}/${configFile}`
);
const jsViteFilePath = joinPathFragments(`${projectRoot}/vite.config.js`);
const tsViteFilePath = joinPathFragments(`${projectRoot}/vite.config.ts`);

return configFile
? joinPathFragments(`${workspaceRoot}/${configFile}`)
: existsSync(joinPathFragments(`${projectRoot}/vite.config.ts`))
? joinPathFragments(`${projectRoot}/vite.config.ts`)
: existsSync(joinPathFragments(`${projectRoot}/vite.config.js`))
? joinPathFragments(`${projectRoot}/vite.config.js`)
? customViteFilePath
: tree?.exists(tsViteFilePath) || existsSync(tsViteFilePath)
? tsViteFilePath
: tree?.exists(jsViteFilePath) || existsSync(jsViteFilePath)
? jsViteFilePath
: undefined;
}

Expand Down

0 comments on commit 6b6577a

Please sign in to comment.