chore(testing): add lerna-smoke-tests (#14347)
This commit is contained in:
parent
da4959a324
commit
965c638d8d
@ -147,6 +147,11 @@ jobs:
|
||||
NX_E2E_RUN_CYPRESS: 'false'
|
||||
NX_VERBOSE_LOGGING: 'false'
|
||||
steps:
|
||||
- run:
|
||||
name: Configure git metadata (needed for lerna smoke tests)
|
||||
command: |
|
||||
git config --global user.email test@test.com
|
||||
git config --global user.name "Test Test"
|
||||
- run:
|
||||
name: Set dynamic nx run variable
|
||||
command: |
|
||||
@ -192,7 +197,7 @@ jobs:
|
||||
pids+=($!)
|
||||
|
||||
(yarn nx affected --target=build --base=$NX_BASE --head=$NX_HEAD --parallel=3 &&
|
||||
npx nx affected --target=e2e --base=$NX_BASE --head=$NX_HEAD --exclude=e2e-storybook,e2e-storybook-angular,e2e-react-native,e2e-detox --parallel=1) &
|
||||
npx nx affected --target=e2e --base=$NX_BASE --head=$NX_HEAD --exclude=e2e-storybook,e2e-storybook-angular --parallel=1) &
|
||||
pids+=($!)
|
||||
|
||||
for pid in "${pids[@]}"; do
|
||||
@ -213,27 +218,11 @@ jobs:
|
||||
echo "export NX_RUN_GROUP=\"run-group-macos-$CIRCLE_WORKFLOW_ID\";" >> $BASH_ENV
|
||||
- setup:
|
||||
os: macos
|
||||
- nx/set-shas:
|
||||
main-branch-name: 'master'
|
||||
- run:
|
||||
name: Check if "detox" or "react-native" were modified directly
|
||||
name: Run E2E Tests for macOS
|
||||
# FIXME: remove --exclude=e2e-detox once we have a fix for the detox tests
|
||||
command: |
|
||||
COUNT=`git diff --name-only $NX_BASE $NX_HEAD | (grep -E 'packages/detox|packages/react-native|e2e/detox|e2e/react-native' || true) | wc -l`
|
||||
if [[ $COUNT -gt 0 ]]; then
|
||||
echo "React Native and Detox were touched directly"
|
||||
echo "export E2E_AFFECTED=true;" >> $BASH_ENV
|
||||
else
|
||||
echo "React Native and Detox were not touched directly"
|
||||
echo "export E2E_AFFECTED=false;" >> $BASH_ENV
|
||||
fi
|
||||
- run:
|
||||
name: Run E2E Tests
|
||||
command: |
|
||||
if $E2E_AFFECTED; then
|
||||
npx nx affected --target=e2e --base=$NX_BASE --head=$NX_HEAD --exclude=e2e-make-angular-cli-faster,e2e-detox,e2e-js,e2e-next,e2e-workspace-create,e2e-nx-run,e2e-nx-misc,e2e-react,e2e-web,e2e-webpack,e2e-rollup,e2e-esbuild,e2e-angular-extensions,e2e-angular-core,e2e-nx-plugin,e2e-cypress,e2e-node,e2e-linter,e2e-jest,e2e-add-nx-to-monorepo,nx-dev-e2e,e2e-nx-init,e2e-graph-client,e2e-vite,e2e-cra-to-nx,e2e-storybook,e2e-storybook-angular --parallel=1;
|
||||
else
|
||||
echo "Skipping E2E tests";
|
||||
fi
|
||||
npx nx run-many -t e2e-macos --parallel=1 --exclude=e2e-detox
|
||||
no_output_timeout: 45m
|
||||
|
||||
# -------------------------
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
"sourceRoot": "e2e/detox",
|
||||
"projectType": "application",
|
||||
"targets": {
|
||||
"e2e": {},
|
||||
"e2e-macos": {},
|
||||
"run-e2e-tests": {}
|
||||
},
|
||||
"implicitDependencies": ["detox"]
|
||||
|
||||
11
e2e/lerna-smoke-tests/jest.config.ts
Normal file
11
e2e/lerna-smoke-tests/jest.config.ts
Normal file
@ -0,0 +1,11 @@
|
||||
/* eslint-disable */
|
||||
export default {
|
||||
transform: {
|
||||
'^.+\\.[tj]sx?$': 'ts-jest',
|
||||
},
|
||||
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html'],
|
||||
maxWorkers: 1,
|
||||
globals: { 'ts-jest': { tsconfig: '<rootDir>/tsconfig.spec.json' } },
|
||||
displayName: 'e2e-lerna-smoke-tests',
|
||||
preset: '../../jest.preset.js',
|
||||
};
|
||||
11
e2e/lerna-smoke-tests/project.json
Normal file
11
e2e/lerna-smoke-tests/project.json
Normal file
@ -0,0 +1,11 @@
|
||||
{
|
||||
"name": "e2e-lerna-smoke-tests",
|
||||
"$schema": "../../node_modules/nx/schemas/project-schema.json",
|
||||
"sourceRoot": "e2e/lerna-smoke-tests",
|
||||
"projectType": "application",
|
||||
"targets": {
|
||||
"e2e": {},
|
||||
"run-e2e-tests": {}
|
||||
},
|
||||
"implicitDependencies": ["nx", "devkit"]
|
||||
}
|
||||
79
e2e/lerna-smoke-tests/src/lerna-smoke-tests.test.ts
Normal file
79
e2e/lerna-smoke-tests/src/lerna-smoke-tests.test.ts
Normal file
@ -0,0 +1,79 @@
|
||||
/**
|
||||
* These minimal smoke tests are here to ensure that we do not break assumptions on the lerna side
|
||||
* when making updates to nx or @nrwl/devkit.
|
||||
*/
|
||||
|
||||
import {
|
||||
cleanupLernaWorkspace,
|
||||
newLernaWorkspace,
|
||||
runLernaCLI,
|
||||
tmpProjPath,
|
||||
updateJson,
|
||||
} from '@nrwl/e2e/utils';
|
||||
|
||||
expect.addSnapshotSerializer({
|
||||
serialize(str: string) {
|
||||
return (
|
||||
str
|
||||
// Not all package managers print the package.json path in the output
|
||||
.replace(tmpProjPath(), '')
|
||||
.replace('/private', '')
|
||||
.replace('/packages/package-1', '')
|
||||
// We trim each line to reduce the chances of snapshot flakiness
|
||||
.split('\n')
|
||||
.map((r) => r.trim())
|
||||
.join('\n')
|
||||
);
|
||||
},
|
||||
test(val: string) {
|
||||
return val != null && typeof val === 'string';
|
||||
},
|
||||
});
|
||||
|
||||
describe('Lerna Smoke Tests', () => {
|
||||
beforeAll(() => newLernaWorkspace());
|
||||
afterAll(() => cleanupLernaWorkspace());
|
||||
|
||||
// `lerna repair` builds on top of `nx repair` and runs all of its generators
|
||||
describe('lerna repair', () => {
|
||||
// If this snapshot fails it means that nx repair generators are making assumptions which don't hold true for lerna workspaces
|
||||
it('should complete successfully on a new lerna workspace', async () => {
|
||||
expect(runLernaCLI(`repair`)).toMatchInlineSnapshot(`
|
||||
|
||||
> Lerna No changes were necessary. This workspace is up to date!
|
||||
|
||||
|
||||
`);
|
||||
}, 1000000);
|
||||
});
|
||||
|
||||
// `lerna run` delegates to the nx task runner behind the scenes
|
||||
describe('lerna run', () => {
|
||||
it('should complete successfully on a new lerna workspace', async () => {
|
||||
runLernaCLI('create package-1 -y');
|
||||
updateJson('packages/package-1/package.json', (json) => ({
|
||||
...json,
|
||||
scripts: {
|
||||
...(json.scripts || {}),
|
||||
'print-name': 'echo test-package-1',
|
||||
},
|
||||
}));
|
||||
|
||||
expect(runLernaCLI(`run print-name`)).toMatchInlineSnapshot(`
|
||||
|
||||
> package-1:print-name
|
||||
|
||||
> package-1@0.0.0 print-name
|
||||
> echo test-package-1
|
||||
test-package-1
|
||||
|
||||
|
||||
|
||||
> Lerna (powered by Nx) Successfully ran target print-name for project package-1
|
||||
|
||||
|
||||
|
||||
`);
|
||||
}, 1000000);
|
||||
});
|
||||
});
|
||||
13
e2e/lerna-smoke-tests/tsconfig.json
Normal file
13
e2e/lerna-smoke-tests/tsconfig.json
Normal file
@ -0,0 +1,13 @@
|
||||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"types": ["node", "jest"]
|
||||
},
|
||||
"include": [],
|
||||
"files": [],
|
||||
"references": [
|
||||
{
|
||||
"path": "./tsconfig.spec.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
20
e2e/lerna-smoke-tests/tsconfig.spec.json
Normal file
20
e2e/lerna-smoke-tests/tsconfig.spec.json
Normal file
@ -0,0 +1,20 @@
|
||||
{
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../../dist/out-tsc",
|
||||
"module": "commonjs",
|
||||
"types": ["jest", "node"]
|
||||
},
|
||||
"include": [
|
||||
"**/*.test.ts",
|
||||
"**/*.spec.ts",
|
||||
"**/*.spec.tsx",
|
||||
"**/*.test.tsx",
|
||||
"**/*.spec.js",
|
||||
"**/*.test.js",
|
||||
"**/*.spec.jsx",
|
||||
"**/*.test.jsx",
|
||||
"**/*.d.ts",
|
||||
"jest.config.ts"
|
||||
]
|
||||
}
|
||||
@ -4,7 +4,7 @@
|
||||
"sourceRoot": "e2e/react-native",
|
||||
"projectType": "application",
|
||||
"targets": {
|
||||
"e2e": {},
|
||||
"e2e-macos": {},
|
||||
"run-e2e-tests": {}
|
||||
},
|
||||
"implicitDependencies": ["react-native"]
|
||||
|
||||
@ -7,6 +7,7 @@ import {
|
||||
workspaceRoot,
|
||||
} from '@nrwl/devkit';
|
||||
import { angularCliVersion } from '@nrwl/workspace/src/utils/versions';
|
||||
import { dump } from '@zkochan/js-yaml';
|
||||
import { ChildProcess, exec, execSync, ExecSyncOptions } from 'child_process';
|
||||
import {
|
||||
copySync,
|
||||
@ -46,7 +47,8 @@ export function getPublishedVersion(): string {
|
||||
export function detectPackageManager(dir: string = ''): PackageManager {
|
||||
return existsSync(join(dir, 'yarn.lock'))
|
||||
? 'yarn'
|
||||
: existsSync(join(dir, 'pnpm-lock.yaml'))
|
||||
: existsSync(join(dir, 'pnpm-lock.yaml')) ||
|
||||
existsSync(join(dir, 'pnpm-workspace.yaml'))
|
||||
? 'pnpm'
|
||||
: 'npm';
|
||||
}
|
||||
@ -374,6 +376,106 @@ export function newProject({
|
||||
}
|
||||
}
|
||||
|
||||
export function newLernaWorkspace({
|
||||
name = uniq('lerna-proj'),
|
||||
packageManager = getSelectedPackageManager(),
|
||||
} = {}): string {
|
||||
try {
|
||||
const projScope = name;
|
||||
projName = name;
|
||||
|
||||
const pm = getPackageManagerCommand({ packageManager });
|
||||
|
||||
createNonNxProjectDirectory(projScope, packageManager !== 'pnpm');
|
||||
|
||||
if (packageManager === 'pnpm') {
|
||||
updateFile(
|
||||
'pnpm-workspace.yaml',
|
||||
dump({
|
||||
packages: ['packages/*'],
|
||||
})
|
||||
);
|
||||
updateFile(
|
||||
'.npmrc',
|
||||
'prefer-frozen-lockfile=false\nstrict-peer-dependencies=false\nauto-install-peers=true'
|
||||
);
|
||||
}
|
||||
|
||||
if (process.env.NX_VERBOSE_LOGGING == 'true') {
|
||||
logInfo(`NX`, `E2E test has created a lerna workspace: ${tmpProjPath()}`);
|
||||
}
|
||||
|
||||
// We need to force the real latest version of lerna to depend on our locally published version of nx
|
||||
updateJson(`package.json`, (json) => {
|
||||
// yarn workspaces can only be enabled in private projects
|
||||
json.private = true;
|
||||
|
||||
const nxVersion = getPublishedVersion();
|
||||
const overrides = {
|
||||
...json.overrides,
|
||||
nx: nxVersion,
|
||||
'@nrwl/devkit': nxVersion,
|
||||
};
|
||||
if (packageManager === 'pnpm') {
|
||||
json.pnpm = {
|
||||
...json.pnpm,
|
||||
overrides: {
|
||||
...json.pnpm?.overrides,
|
||||
...overrides,
|
||||
},
|
||||
};
|
||||
} else if (packageManager === 'yarn') {
|
||||
json.resolutions = {
|
||||
...json.resolutions,
|
||||
...overrides,
|
||||
};
|
||||
} else {
|
||||
json.overrides = overrides;
|
||||
}
|
||||
return json;
|
||||
});
|
||||
|
||||
/**
|
||||
* Again, in order to ensure we override the required version relationships, we first install lerna as a devDep
|
||||
* before running `lerna init`.
|
||||
*/
|
||||
execSync(
|
||||
`${pm.addDev} lerna@${getLatestLernaVersion()}${
|
||||
packageManager === 'pnpm'
|
||||
? ' --workspace-root'
|
||||
: packageManager === 'yarn'
|
||||
? ' -W'
|
||||
: ''
|
||||
}`,
|
||||
{
|
||||
cwd: tmpProjPath(),
|
||||
stdio: isVerbose() ? 'inherit' : 'pipe',
|
||||
env: { CI: 'true', ...process.env },
|
||||
encoding: 'utf-8',
|
||||
}
|
||||
);
|
||||
|
||||
execSync(`${pm.runLerna} init`, {
|
||||
cwd: tmpProjPath(),
|
||||
stdio: isVerbose() ? 'inherit' : 'pipe',
|
||||
env: { CI: 'true', ...process.env },
|
||||
encoding: 'utf-8',
|
||||
});
|
||||
|
||||
execSync(pm.install, {
|
||||
cwd: tmpProjPath(),
|
||||
stdio: isVerbose() ? 'inherit' : 'pipe',
|
||||
env: { CI: 'true', ...process.env },
|
||||
encoding: 'utf-8',
|
||||
});
|
||||
|
||||
return projScope;
|
||||
} catch (e) {
|
||||
logError(`Failed to set up lerna workspace for e2e tests.`, e.message);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
const KILL_PORT_DELAY = 5000;
|
||||
|
||||
export async function killPort(port: number): Promise<boolean> {
|
||||
@ -416,6 +518,14 @@ export async function cleanupProject(opts?: RunCmdOpts) {
|
||||
}
|
||||
}
|
||||
|
||||
export function cleanupLernaWorkspace() {
|
||||
if (isCI) {
|
||||
try {
|
||||
removeSync(tmpProjPath());
|
||||
} catch (e) {}
|
||||
}
|
||||
}
|
||||
|
||||
export function runCypressTests() {
|
||||
if (process.env.NX_E2E_RUN_CYPRESS === 'true') {
|
||||
ensureCypressInstallation();
|
||||
@ -629,6 +739,42 @@ export function runCLI(
|
||||
}
|
||||
}
|
||||
|
||||
export function runLernaCLI(
|
||||
command: string,
|
||||
opts: RunCmdOpts = {
|
||||
silenceError: false,
|
||||
env: undefined,
|
||||
}
|
||||
): string {
|
||||
try {
|
||||
const pm = getPackageManagerCommand();
|
||||
const logs = execSync(`${pm.runLerna} ${command}`, {
|
||||
cwd: opts.cwd || tmpProjPath(),
|
||||
env: { CI: 'true', ...(opts.env || getStrippedEnvironmentVariables()) },
|
||||
encoding: 'utf-8',
|
||||
stdio: 'pipe',
|
||||
maxBuffer: 50 * 1024 * 1024,
|
||||
});
|
||||
const r = stripConsoleColors(logs);
|
||||
|
||||
if (isVerbose()) {
|
||||
console.log(logs);
|
||||
}
|
||||
|
||||
return r;
|
||||
} catch (e) {
|
||||
if (opts.silenceError) {
|
||||
return stripConsoleColors(e.stdout?.toString() + e.stderr?.toString());
|
||||
} else {
|
||||
logError(
|
||||
`Original command: ${command}`,
|
||||
`${e.stdout?.toString()}\n\n${e.stderr?.toString()}`
|
||||
);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove log colors for fail proof string search
|
||||
* @param log
|
||||
@ -882,6 +1028,7 @@ export function getPackageManagerCommand({
|
||||
addProd: string;
|
||||
addDev: string;
|
||||
list: string;
|
||||
runLerna: string;
|
||||
} {
|
||||
const npmMajorVersion = getNpmMajorVersion();
|
||||
const publishedVersion = getPublishedVersion();
|
||||
@ -899,6 +1046,7 @@ export function getPackageManagerCommand({
|
||||
addProd: `npm install --legacy-peer-deps`,
|
||||
addDev: `npm install --legacy-peer-deps -D`,
|
||||
list: 'npm ls --depth 10',
|
||||
runLerna: `npx lerna`,
|
||||
},
|
||||
yarn: {
|
||||
// `yarn create nx-workspace` is failing due to wrong global path
|
||||
@ -911,6 +1059,7 @@ export function getPackageManagerCommand({
|
||||
addProd: `yarn add`,
|
||||
addDev: `yarn add -D`,
|
||||
list: 'npm ls --depth 10',
|
||||
runLerna: `yarn lerna`,
|
||||
},
|
||||
// Pnpm 3.5+ adds nx to
|
||||
pnpm: {
|
||||
@ -923,6 +1072,7 @@ export function getPackageManagerCommand({
|
||||
addProd: `pnpm add`,
|
||||
addDev: `pnpm add -D`,
|
||||
list: 'npm ls --depth 10',
|
||||
runLerna: `pnpm exec lerna`,
|
||||
},
|
||||
}[packageManager.trim() as PackageManager];
|
||||
}
|
||||
@ -932,6 +1082,11 @@ function getNpmMajorVersion(): string {
|
||||
return npmMajorVersion;
|
||||
}
|
||||
|
||||
function getLatestLernaVersion(): string {
|
||||
const lernaVersion = execSync(`npm view lerna version`).toString().trim();
|
||||
return lernaVersion;
|
||||
}
|
||||
|
||||
export const packageManagerLockFile = {
|
||||
npm: 'package-lock.json',
|
||||
yarn: 'yarn.lock',
|
||||
|
||||
33
nx.json
33
nx.json
@ -95,6 +95,39 @@
|
||||
{
|
||||
"env": "SELECTED_CLI"
|
||||
},
|
||||
{
|
||||
"env": "SELECTED_PM"
|
||||
},
|
||||
{
|
||||
"env": "NX_E2E_CI_CACHE_KEY"
|
||||
}
|
||||
],
|
||||
"options": {
|
||||
"commands": [
|
||||
{
|
||||
"command": "yarn e2e-start-local-registry"
|
||||
},
|
||||
{
|
||||
"command": "yarn e2e-build-package-publish"
|
||||
},
|
||||
{
|
||||
"command": "nx run-e2e-tests {projectName}"
|
||||
}
|
||||
],
|
||||
"parallel": false
|
||||
}
|
||||
},
|
||||
"e2e-macos": {
|
||||
"executor": "nx:run-commands",
|
||||
"inputs": [
|
||||
"default",
|
||||
"^production",
|
||||
{
|
||||
"env": "SELECTED_CLI"
|
||||
},
|
||||
{
|
||||
"env": "SELECTED_PM"
|
||||
},
|
||||
{
|
||||
"env": "NX_E2E_CI_CACHE_KEY"
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user