Skip to content

Commit

Permalink
feat(it-tests): test schematics with yarn 1
Browse files Browse the repository at this point in the history
  • Loading branch information
vscaiceanu-1a authored and mrednic-1A committed Mar 27, 2024
1 parent 1f5c655 commit 232a975
Show file tree
Hide file tree
Showing 10 changed files with 156 additions and 51 deletions.
12 changes: 11 additions & 1 deletion .github/workflows/it-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ jobs:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest]
packageManager: [yarn, npm]
packageManager: [yarn, npm, yarn1]
testEnvironment: [o3r-project-with-app]
runs-on: ${{ matrix.os }}
env:
Expand Down Expand Up @@ -104,9 +104,19 @@ jobs:
npx --yes wait-on http://127.0.0.1:4873 -t 180000
fi
shell: bash
- name: Rename .npmrc for yarn 1
if: matrix.packageManager == 'yarn1'
id: rename-npmrc
run: mv -f .npmrc .npmrc-backup
shell: bash
- name: Test
id: it-tests
run: yarn test-int
- name: Revert .npmrc rename for yarn 1
if: matrix.packageManager == 'yarn1'
id: revert-rename-npmrc
run: mv -f .npmrc-backup .npmrc
shell: bash
- name: Zip generated app on failure
if: failure() && steps.it-tests.conclusion == 'failure'
run: |
Expand Down
52 changes: 35 additions & 17 deletions packages/@ama-sdk/create/src/index.it.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@
* @jest-environment @o3r/test-helpers/jest-environment
* @jest-environment-o3r-app-folder test-create-sdk
* @jest-environment-o3r-type blank
* @jest-environment-o3r-package-scope ama-sdk-create
*/
const o3rEnvironment = globalThis.o3rEnvironment;

import {
getDefaultExecSyncOptions,
getPackageManager,
getYarnVersionFromRoot,
isYarn1Enforced,
packageManagerCreate,
packageManagerExec,
packageManagerInstall,
Expand All @@ -26,10 +27,20 @@ const execAppOptions = getDefaultExecSyncOptions();
const packageManager = getPackageManager();

describe('Create new sdk command', () => {
beforeEach(() => {

const setupLocalTest = (_sdkFolderIndex: number) => {
const isYarnTest = packageManager.startsWith('yarn');
const yarnVersion = isYarnTest ? getYarnVersionFromRoot(process.cwd()) || 'latest' : undefined;
const yarnVersion = o3rEnvironment.testEnvironment.packageManagerConfig.yarnVersion;
// const yarnVersion = isYarnTest ? getYarnVersionFromRoot(process.cwd()) || 'latest' : undefined;
sdkFolderPath = o3rEnvironment.testEnvironment.workspacePath;
// const yarnVersion = isYarnTest ? getYarnVersionFromRoot(process.cwd()) || 'latest' : undefined;
// const yarnVersion = globalThis.testEnvironment.packageManagerConfig.yarnVersion;
// sdkFolderPath = globalThis.testEnvironment.workspacePath;

// const isYarnTest = packageManager.startsWith('yarn');
// const testEnv = await prepareTestEnv(projectName + sdkFolderIndex, { type: 'blank', packageScope: 'ama-sdk-create' });
// sdkFolderPath = testEnv.workspacePath;
// const yarnVersion = testEnv.packageManagerConfig.yarnVersion;
sdkPackagePath = path.join(sdkFolderPath, sdkPackageName.replace(/^@/, ''));
execAppOptions.cwd = sdkFolderPath;

Expand All @@ -38,32 +49,32 @@ describe('Create new sdk command', () => {
packageManagerInstall(execAppOptions);

// copy yarnrc config to generated SDK
mkdirSync(sdkPackagePath, {recursive: true});
cpSync(path.join(sdkFolderPath, '.yarnrc.yml'), path.join(sdkPackagePath, '.yarnrc.yml'));
cpSync(path.join(sdkFolderPath, '.yarn'), path.join(sdkPackagePath, '.yarn'), {recursive: true});
mkdirSync(sdkPackagePath, { recursive: true });
const yarnConfigFile = isYarn1Enforced() ? '.yarnrc' : '.yarnrc.yml';
cpSync(path.join(sdkFolderPath, yarnConfigFile), path.join(sdkPackagePath, yarnConfigFile));
cpSync(path.join(sdkFolderPath, '.yarn'), path.join(sdkPackagePath, '.yarn'), { recursive: true });
fs.writeFileSync(path.join(sdkPackagePath, 'yarn.lock'), '');
} else {
// copy npmrc config to generated SDK
mkdirSync(sdkPackagePath, { recursive: true });
cpSync(path.join(sdkFolderPath, '.npmrc'), path.join(sdkPackagePath, '.npmrc'));
}
});

beforeEach(() => {
cpSync(path.join(__dirname, '..', 'testing', 'mocks', 'MOCK_swagger_updated.yaml'), path.join(sdkFolderPath, 'swagger-spec.yml'));
});
};

test('should generate a full SDK when the specification is provided', () => {
setupLocalTest(1);
expect(() =>
packageManagerCreate({
script: '@ama-sdk',
args: ['typescript', sdkPackageName, '--package-manager', packageManager, '--spec-path', path.join(sdkFolderPath, 'swagger-spec.yml')]
}, execAppOptions)
}, execAppOptions, !isYarn1Enforced() ? 'npm' : undefined)
).not.toThrow();
expect(() => packageManagerRun({script: 'build'}, { ...execAppOptions, cwd: sdkPackagePath })).not.toThrow();
expect(() => packageManagerRun({ script: 'build' }, { ...execAppOptions, cwd: sdkPackagePath })).not.toThrow();
});

test('should generate an SDK with no package scope', () => {
setupLocalTest(2);
const packageName = sdkPackageName.replace('@', '').split('/')[1];
const newSdkPackagePath = path.join(sdkFolderPath, packageName);
renameSync(sdkPackagePath, newSdkPackagePath);
Expand All @@ -77,7 +88,11 @@ describe('Create new sdk command', () => {
});

test('should generate an empty SDK ready to be used', () => {
expect(() => packageManagerCreate({script: '@ama-sdk', args: ['typescript', sdkPackageName]}, execAppOptions)).not.toThrow();
setupLocalTest(3);
expect(() => packageManagerCreate({
script: '@ama-sdk',
args: ['typescript', sdkPackageName, '--package-manager', packageManager]
}, execAppOptions, !isYarn1Enforced() ? 'npm' : undefined)).not.toThrow();
expect(() => packageManagerRun({script: 'build'}, { ...execAppOptions, cwd: sdkPackagePath })).not.toThrow();
expect(() =>
packageManagerExec({
Expand All @@ -90,20 +105,23 @@ describe('Create new sdk command', () => {
});

test('should fail when there is an error', () => {
setupLocalTest(4);
expect(() =>
packageManagerCreate({
script: '@ama-sdk',
args: ['typescript', sdkPackageName, '--package-manager', packageManager, '--spec-path','./missing-file.yml']
}, execAppOptions)
args: ['typescript', sdkPackageName, '--package-manager', packageManager, '--spec-path', './missing-file.yml']
}, execAppOptions, !isYarn1Enforced() ? 'npm' : undefined)
).toThrow();
});

test('should use pinned versions when --exact-o3r-version is used', () => {
setupLocalTest(5);
const versionToInstall = isYarn1Enforced() ? '' : `@${o3rEnvironment.testEnvironment.o3rVersion}`;
expect(() =>
packageManagerCreate({
script: `@ama-sdk@${o3rEnvironment.testEnvironment.o3rVersion}`,
script: `@ama-sdk${versionToInstall}`,
args: ['typescript', sdkPackageName, '--exact-o3r-version', '--package-manager', packageManager, '--spec-path', path.join(sdkFolderPath, 'swagger-spec.yml')]
}, execAppOptions)
}, execAppOptions, !isYarn1Enforced() ? 'npm' : undefined)
).not.toThrow();
expect(() => packageManagerRun({script: 'build'}, { ...execAppOptions, cwd: sdkPackagePath })).not.toThrow();
const packageJson = JSON.parse(fs.readFileSync(path.join(sdkPackagePath, 'package.json'), 'utf-8'));
Expand Down
8 changes: 5 additions & 3 deletions packages/@o3r/create/src/index.it.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,14 @@
* @jest-environment @o3r/test-helpers/jest-environment
* @jest-environment-o3r-app-folder test-create-app
* @jest-environment-o3r-type blank
* @jest-environment-o3r-package-scope o3r-create
*/
const o3rEnvironment = globalThis.o3rEnvironment;

import {
getDefaultExecSyncOptions,
getPackageManager,
isYarn1Enforced,
packageManagerCreate,
packageManagerExec,
packageManagerInstall,
Expand All @@ -23,7 +25,7 @@ const workspaceProjectName = 'my-project';

describe('Create new otter project command', () => {
test('should generate a project with an application', async () => {
const { workspacePath, packageManagerConfig, o3rVersion } = o3rEnvironment.testEnvironment;
const { workspacePath, packageManagerConfig } = o3rEnvironment.testEnvironment;
const inAppPath = path.join(workspacePath, workspaceProjectName);
const execWorkspaceOptions = {...defaultExecOptions, cwd: workspacePath };
const execInAppOptions = {...defaultExecOptions, cwd: inAppPath };
Expand All @@ -33,7 +35,7 @@ describe('Create new otter project command', () => {
await fs.mkdir(inAppPath, { recursive: true });
setPackagerManagerConfig(packageManagerConfig, execInAppOptions);

expect(() => packageManagerCreate({ script: `@o3r@${o3rVersion}`, args: [workspaceProjectName, ...createOptions] }, execWorkspaceOptions, 'npm')).not.toThrow();
expect(() => packageManagerCreate({ script: `@o3r`, args: [workspaceProjectName, ...createOptions] }, execWorkspaceOptions, !isYarn1Enforced() ? 'npm' : undefined)).not.toThrow();
expect(existsSync(path.join(inAppPath, 'angular.json'))).toBe(true);
expect(existsSync(path.join(inAppPath, 'package.json'))).toBe(true);
expect(() => packageManagerInstall(execInAppOptions)).not.toThrow();
Expand All @@ -57,7 +59,7 @@ describe('Create new otter project command', () => {
await fs.mkdir(inAppPath, { recursive: true });
setPackagerManagerConfig(packageManagerConfig, execInAppOptions);

expect(() => packageManagerCreate({ script: `@o3r@${o3rVersion}`, args: [workspaceProjectName, ...createOptions] }, execWorkspaceOptions, 'npm')).not.toThrow();
expect(() => packageManagerCreate({ script: `@o3r`, args: [workspaceProjectName, ...createOptions] }, execWorkspaceOptions, !isYarn1Enforced() ? 'npm' : undefined)).not.toThrow();
expect(existsSync(path.join(inAppPath, 'angular.json'))).toBe(true);
expect(existsSync(path.join(inAppPath, 'package.json'))).toBe(true);
expect(() => packageManagerInstall(execInAppOptions)).not.toThrow();
Expand Down
6 changes: 3 additions & 3 deletions packages/@o3r/create/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -201,14 +201,14 @@ const prepareWorkspace = (relativeDirectory = '.', projectPackageManager = 'npm'
cwd
}));
};

const isYarn1 = packageManager === 'yarn' && argv['yarn-version']?.split('.')[0] === '1';
const addOtterFramework = (relativeDirectory = '.', projectPackageManager = 'npm') => {
const cwd = resolve(process.cwd(), relativeDirectory);
const runner = process.platform === 'win32' ? `${projectPackageManager}.cmd` : projectPackageManager;
const options = schematicsCliOptions
.flat();

exitProcessIfErrorInSpawnSync(3, spawnSync(runner, ['exec', 'ng', 'add', `@o3r/core@${exactO3rVersion ? '' : '~'}${version}`, ...(projectPackageManager === 'npm' ? ['--'] : []), ...options], {
exitProcessIfErrorInSpawnSync(3, spawnSync(runner, [isYarn1 ? 'run' : 'exec', 'ng', 'add', `@o3r/core@${exactO3rVersion ? '' : '~'}${version}`,
...((projectPackageManager === 'npm' || isYarn1) ? ['--'] : []), ...options], {
stdio: 'inherit',
cwd,
env: exactO3rVersion && projectPackageManager === 'npm' ? {
Expand Down
6 changes: 3 additions & 3 deletions packages/@o3r/telemetry/src/environment/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,22 @@ import { execSync } from 'node:child_process';
import * as path from 'node:path';

/** Support NPM package managers */
type SupportedPackageManagers = 'npm' | 'yarn';
type SupportedPackageManagers = 'npm' | 'yarn' | 'yarn1';

/**
* Determine if the given packager manager is supported
* @param name Name of the package manager
*/
function isSupportedPackageManager(name?: any): name is SupportedPackageManagers {
return name === 'yarn' || name === 'npm';
return ['yarn', 'yarn1', 'npm'].includes(name);
}

/**
* Get package manager used
*/
function getPackageManager() {
if (isSupportedPackageManager(process.env?.ENFORCED_PACKAGE_MANAGER)) {
return process.env.ENFORCED_PACKAGE_MANAGER;
return (process.env.ENFORCED_PACKAGE_MANAGE === 'npm') ? 'npm' : 'yarn';
}
return (process.env?.npm_execpath?.includes('yarn') && 'yarn') || 'npm';
}
Expand Down
6 changes: 5 additions & 1 deletion packages/@o3r/test-helpers/src/jest-environment/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,12 +48,16 @@ export class JestEnvironmentO3r extends NodeTestEnvironment {
*/
private readonly testEnvironments: Record<string, TestEnvironment> = {};

/** identifier of the package on which the tests are run */
private readonly packageScope: string | undefined;

constructor(config: JestEnvironmentConfig, context: EnvironmentContext) {
super(config, context);
// testEnvironment is undefined now but will be defined when test runs
this.global.o3rEnvironment = {} as typeof this.global.o3rEnvironment;
this.appFolder = context.docblockPragmas['jest-environment-o3r-app-folder'] as string;
this.prepareTestEnvType = context.docblockPragmas['jest-environment-o3r-type'] as PrepareTestEnvType | undefined;
this.packageScope = context.docblockPragmas['jest-environment-o3r-package-scope'] as string | undefined;
}

/**
Expand Down Expand Up @@ -87,7 +91,7 @@ export class JestEnvironmentO3r extends NodeTestEnvironment {
// Create test environment before test starts
if (event.name === 'test_start') {
const appFolder = `${this.appFolder}${this.appIndex++ || ''}`;
this.testEnvironments[event.test.name] = await prepareTestEnv(appFolder, {type: this.prepareTestEnvType});
this.testEnvironments[event.test.name] = await prepareTestEnv(appFolder, {type: this.prepareTestEnvType, packageScope: this.packageScope});
this.global.o3rEnvironment.testEnvironment = this.testEnvironments[event.test.name];
}
// Cleanup test environment after test succeeds
Expand Down
24 changes: 15 additions & 9 deletions packages/@o3r/test-helpers/src/prepare-test-env.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { cpSync, existsSync, mkdirSync, readdirSync, readFileSync, rmSync, statS
import * as path from 'node:path';
import type { PackageJson } from 'type-fest';
import { createTestEnvironmentBlank } from './test-environments/create-test-environment-blank';
import { createWithLock, getPackageManager, type Logger, packageManagerInstall, setPackagerManagerConfig, setupGit } from './utilities/index';
import { createWithLock, getVersionedPackageManager, isYarn1Enforced, type Logger, packageManagerInstall, setPackagerManagerConfig, setupGit } from './utilities/index';
import { createTestEnvironmentOtterProjectWithApp } from './test-environments/create-test-environment-otter-project';
import { O3rCliError } from '@o3r/schematics';

Expand All @@ -15,8 +15,7 @@ export type PrepareTestEnvType = 'blank' | 'o3r-project-with-app';

/**
* Retrieve the version used by yarn and setup at root level
* @param rootFolderPath: path to the folder where to take the configuration from
* @param rootFolderPath
* @param rootFolderPath path to the folder where to take the configuration from
*/
export function getYarnVersionFromRoot(rootFolderPath: string) {
const o3rPackageJson: PackageJson & { generatorDependencies?: Record<string, string> } =
Expand All @@ -31,6 +30,11 @@ export interface PrepareTestEnvOptions {
yarnVersion?: string;
/** Logger to use for logging */
logger?: Logger;
/**
* Scope of package used to run the create command
* Used on yarn1 tests, because it is not able to differetiate from which package scope to run the create
*/
packageScope?: string;
}

/**
Expand All @@ -43,14 +47,15 @@ export async function prepareTestEnv(folderName: string, options?: PrepareTestEn
const logger = options?.logger || console;
const yarnVersionParam = options?.yarnVersion;
const rootFolderPath = process.cwd();
const itTestsFolderPath = path.resolve(rootFolderPath, '..', 'it-tests');
const itTestsFolderPath = path.resolve(rootFolderPath, '..', 'it-tests', options?.packageScope || '');
const workspacePath = path.resolve(itTestsFolderPath, folderName);
const globalFolderPath = path.resolve(rootFolderPath, '.cache', 'test-app');
const cacheFolderPath = path.resolve(globalFolderPath, 'cache');
const o3rVersion = '999.0.0';

JSON.parse(readFileSync(path.join(rootFolderPath, 'packages', '@o3r', 'core', 'package.json')).toString());
const yarnVersion: string = yarnVersionParam || getYarnVersionFromRoot(rootFolderPath);
const yarn1Version = execSync('npm view yarn version', { encoding: 'utf8' }).trim();
const yarnVersion: string = yarnVersionParam || (isYarn1Enforced() && yarn1Version) || getYarnVersionFromRoot(rootFolderPath);
const execAppOptions: ExecSyncOptions = {
cwd: workspacePath,
stdio: 'inherit',
Expand All @@ -77,17 +82,18 @@ export async function prepareTestEnv(folderName: string, options?: PrepareTestEn
const packageManagerConfig = {
yarnVersion,
globalFolderPath,
registry: 'http://127.0.0.1:4873'
registry: 'http://127.0.0.1:4873',
...(isYarn1Enforced() ? {packageScope: options?.packageScope} : {})
};

// Create it-tests folder
if (!existsSync(itTestsFolderPath)) {
logger.debug?.(`Creating it-tests folder`);
await createWithLock(() => {
mkdirSync(itTestsFolderPath);
mkdirSync(itTestsFolderPath, { recursive: true });
setPackagerManagerConfig(packageManagerConfig, {...execAppOptions, cwd: itTestsFolderPath});
return Promise.resolve();
}, {lockFilePath: `${itTestsFolderPath}.lock`, cwd: path.join(rootFolderPath, '..'), appDirectory: 'it-tests'});
}, {lockFilePath: `${itTestsFolderPath}.lock`, cwd: path.join(rootFolderPath, '..'), appDirectory: path.join('it-tests', options?.packageScope || '')});
}

// Remove existing app
Expand All @@ -109,7 +115,7 @@ export async function prepareTestEnv(folderName: string, options?: PrepareTestEn
let isInWorkspace = false;
let untouchedProject: undefined | string;
let untouchedProjectPath: undefined | string;
const appDirectory = `${type}-${getPackageManager()}`;
const appDirectory = `${type}-${getVersionedPackageManager()}`;
switch (type) {
case 'blank': {
await createTestEnvironmentBlank({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
createWithLock,
CreateWithLockOptions,
getPackageManager,
isYarn1Enforced,
type Logger,
PackageManagerConfig,
packageManagerCreate,
Expand Down Expand Up @@ -74,9 +75,10 @@ export async function createTestEnvironmentOtterProjectWithApp(inputOptions: Par
try { mkdirSync(appFolderPath, { recursive: true }); } catch { }
setPackagerManagerConfig(options, execAppOptions);

const versionToInstall = isYarn1Enforced() ? '' : `@${o3rVersion}`;
// Create Project
const createOptions = ['--package-manager', getPackageManager(), '--skip-confirmation', ...(options.yarnVersion ? ['--yarn-version', options.yarnVersion] : [])];
packageManagerCreate({ script: `@o3r@${o3rVersion}`, args: [options.appDirectory, ...createOptions] }, { ...execAppOptions, cwd: options.cwd}, 'npm');
packageManagerCreate({ script: `@o3r${versionToInstall}`, args: [options.appDirectory, ...createOptions] }, { ...execAppOptions, cwd: options.cwd}, !isYarn1Enforced() ? 'npm' : undefined);
const gitIgnorePath = path.join(appFolderPath, '.gitignore');
if (existsSync(gitIgnorePath)) {
const gitIgnore = readFileSync(gitIgnorePath, { encoding: 'utf8' });
Expand Down
6 changes: 5 additions & 1 deletion packages/@o3r/test-helpers/src/utilities/locker.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { existsSync, readFileSync, rmSync, statSync, watch, writeFileSync } from 'node:fs';
import { existsSync, mkdirSync, readFileSync, rmSync, statSync, watch, writeFileSync } from 'node:fs';
import * as path from 'node:path';

export interface LockerOptions {
Expand Down Expand Up @@ -39,6 +39,10 @@ export class Locker {
public lock(): boolean {
const pid = String(process.pid);
try {
const locDirPath = path.dirname(this.options.lockFilePath);
if (!existsSync(locDirPath)) {
mkdirSync(locDirPath, {recursive: true});
}
writeFileSync(this.options.lockFilePath, pid, {flag: this.isLockExpired() ? 'w' : 'wx'});
// Need to check if the file was created by this process
return readFileSync(this.options.lockFilePath, {encoding: 'utf8'}) === pid;
Expand Down
Loading

0 comments on commit 232a975

Please sign in to comment.