diff --git a/.changeset/large-plums-dress.md b/.changeset/large-plums-dress.md new file mode 100644 index 000000000..dd32cb40e --- /dev/null +++ b/.changeset/large-plums-dress.md @@ -0,0 +1,5 @@ +--- +"create-lz-oapp": patch +--- + +Add ability run in CI (non-interactive) mode diff --git a/.eslintignore b/.eslintignore index 7edbcc827..63f925619 100644 --- a/.eslintignore +++ b/.eslintignore @@ -7,3 +7,4 @@ node_modules *.yaml Dockerfile Makefile +*.bats diff --git a/.gitmodules b/.gitmodules index 403988df8..8616f5d62 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,3 +4,12 @@ [submodule "toolbox-foundry/ds-test"] path = packages/toolbox-foundry/src/ds-test url = https://github.com/dapphub/ds-test +[submodule "tests-user/bats-core"] + path = tests-user/lib/bats-core + url = https://github.com/bats-core/bats-core.git +[submodule "tests-user/bats-support"] + path = tests-user/lib/bats-support + url = https://github.com/bats-core/bats-support.git +[submodule "tests-user/bats-assert"] + path = tests-user/lib/bats-assert + url = https://github.com/bats-core/bats-assert.git diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index 2ddff7d15..b73119ac2 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -228,6 +228,10 @@ pnpm test:user This will spin up a local NPM registry (available on [localhost:4873](http://localhost:4873) for debugging purposes), publish all packages locally and run the test suite. +The tests themselves are written using [BATS - _Bash Automated Testing System_](https://github.com/bats-core/bats-core) ([Tutorial & more docs here](https://bats-core.readthedocs.io/en/stable/)) in combination with standard assertions from [`bats-assert`](https://github.com/bats-core/bats-assert). + +The test suites can be found under `./tests-user/tests` directory. + #### Using local NPM registry The local NPM registry can also be used to simulate arbitrary user flows without needing to link or publish packages to NPM. To do this, follow these steps: diff --git a/docker-compose.registry.yaml b/docker-compose.registry.yaml index 3c498d2aa..253c8a00c 100644 --- a/docker-compose.registry.yaml +++ b/docker-compose.registry.yaml @@ -22,7 +22,16 @@ services: healthcheck: interval: 2s retries: 10 - test: ["CMD", "wget", "--output-document", "--tries=1", "--no-verbose", "--spider", "http://0.0.0.0:4873/-/ping"] + test: + [ + "CMD", + "wget", + "--output-document", + "--tries=1", + "--no-verbose", + "--spider", + "http://0.0.0.0:4873/-/ping", + ] stop_grace_period: 120s volumes: - ./verdaccio.yaml:/verdaccio/conf/config.yaml @@ -40,9 +49,9 @@ services: - npm-registry # Here we build and publish all the packages locally, # including any pending changesets. - # + # # Even though we enabled anonymous publishing in verdaccio, - # we need to specify some sort of an auth token + # we need to specify some sort of an auth token # since we are trying to publish scoped packages. This can be anything, # any non-empty string will do command: @@ -67,13 +76,29 @@ services: depends_on: publish: condition: service_completed_successfully + # create-lz-oapp allows us to specify the repository/ref we pull the examples from + # + # In order to test the version on this branch in github actions, + # we'll set these based on the default variables github gives us + # + # If these are not provided, for example if running on a local machine, + # we'll default them to our repository and and empty ref + environment: + - LAYERZERO_EXAMPLES_REPOSITORY_URL=git@github.com:${GITHUB_REPOSITORY:-LayerZero-Labs/devtools} + - LAYERZERO_EXAMPLES_REPOSITORY_REF=${GITHUB_REF_NAME} + working_dir: /app command: - /bin/bash - -c - | pnpm config set registry http://npm-registry:4873/ - - ./tests-user/create-lz-oapp.sh - volumes: - - ./tests-user:/tests-user + /app/tests-user/lib/bats-core/bin/bats --verbose-run --recursive ./tests-user/tests + volumes: + # If we want to clone from github.com, we'll need its public keys added to our SSH config + # otherwise git clone would trigger an interactive prompt asking us to add a server fingerprint + # + # See more here https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/githubs-ssh-key-fingerprints + - ./tests-user/ssh/known_hosts:/root/.ssh/known_hosts + # The testing library and test suites + - ./tests-user:/app/tests-user diff --git a/packages/create-lz-oapp/src/components/error.tsx b/packages/create-lz-oapp/src/components/error.tsx new file mode 100644 index 000000000..ef9d78021 --- /dev/null +++ b/packages/create-lz-oapp/src/components/error.tsx @@ -0,0 +1,77 @@ +import React from "react"; +import type { Config } from "@/types"; +import { Box, Text } from "ink"; +import { + BadGitRefError, + DestinationNotEmptyError, + DownloadError, + MissingGitRefError, +} from "@/utilities/cloning"; + +interface ErrorMessageProps { + config: Config; + error?: unknown; +} + +export const ErrorMessage: React.FC = ({ + config, + error, +}) => { + if (error == null) return null; + + switch (true) { + case error instanceof DestinationNotEmptyError: + return ( + + Destination directory {config.destination} is not + empty + + ); + + case error instanceof BadGitRefError: + return ( + + The example {config.example.label} has its + repository URL malformed: ' + {config.example.repository}' does not look like a + valid repository + + ); + + case error instanceof MissingGitRefError: + return ( + + The example {config.example.label} does not seem to + exist in the repository + + ); + + case error instanceof DownloadError: + return ( + + There was a problem downloading the example + ○ Please check your internet connection + + ○ Please check that the example exists ( + {config.example.repository}) + + + ); + + case error instanceof Error: + return ; + + default: + return ; + } +}; + +export const DefaultErrorMessage: React.FC<{ error: Error | string }> = ({ + error, +}) => { + return ( + + {String(error)} + + ); +}; diff --git a/packages/create-lz-oapp/src/components/setup.tsx b/packages/create-lz-oapp/src/components/setup.tsx index e6887cb3e..f90d6d51d 100644 --- a/packages/create-lz-oapp/src/components/setup.tsx +++ b/packages/create-lz-oapp/src/components/setup.tsx @@ -1,16 +1,11 @@ import React, { useEffect } from "react"; import type { Config } from "@/types"; -import { Box, Text } from "ink"; -import { - BadGitRefError, - DestinationNotEmptyError, - DownloadError, - MissingGitRefError, - cloneExample, -} from "@/utilities/cloning"; +import { Box } from "ink"; +import { cloneExample } from "@/utilities/cloning"; import { Progress } from "./progress"; import { installDependencies } from "@/utilities/installation"; import { useTask } from "@/utilities/tasks"; +import { ErrorMessage } from "./error"; interface Props { config: Config; @@ -46,59 +41,3 @@ export const Setup: React.FC = ({ config }) => { ); }; - -interface ErrorMessageProps { - config: Config; - error?: unknown; -} - -const ErrorMessage: React.FC = ({ config, error }) => { - if (error == null) return null; - - switch (true) { - case error instanceof DestinationNotEmptyError: - return ( - - Destination directory {config.destination} is not - empty - - ); - - case error instanceof BadGitRefError: - return ( - - The example {config.example.label} has its - repository URL malformed: ' - {config.example.repository}' does not look like a - valid repository - - ); - - case error instanceof MissingGitRefError: - return ( - - The example {config.example.label} does not seem to - exist in the repository - - ); - - case error instanceof DownloadError: - return ( - - There was a problem downloading the example - ○ Please check your internet connection - - ○ Please check that the example exists ( - {config.example.repository}) - - - ); - - default: - return ( - - An unknown error happened: {String(error)} - - ); - } -}; diff --git a/packages/create-lz-oapp/src/config.ts b/packages/create-lz-oapp/src/config.ts index 8e0f79cee..3b426e86a 100644 --- a/packages/create-lz-oapp/src/config.ts +++ b/packages/create-lz-oapp/src/config.ts @@ -1,4 +1,5 @@ import type { Example, PackageManager } from '@/types' +import { isPackageManagerAvailable } from './utilities/installation' /** * To enable example development in a custom repository @@ -34,19 +35,29 @@ export const EXAMPLES: Example[] = [ export const PACKAGE_MANAGERS: PackageManager[] = [ { - command: 'npm', + id: 'npm', + executable: 'npm', + args: ['install', '--legacy-peer-deps'], label: 'npm', }, { - command: 'yarn', + id: 'yarn', + executable: 'yarn', + args: ['install'], label: 'yarn', }, { - command: 'pnpm', + id: 'pnpm', + executable: 'pnpm', + args: ['install'], label: 'pnpm', }, { - command: 'bun', + id: 'bun', + executable: 'bun', + args: ['install'], label: 'bun', }, ] + +export const AVAILABLE_PACKAGE_MANAGERS = PACKAGE_MANAGERS.filter(isPackageManagerAvailable) diff --git a/packages/create-lz-oapp/src/index.tsx b/packages/create-lz-oapp/src/index.tsx index 822dad850..faae68c27 100644 --- a/packages/create-lz-oapp/src/index.tsx +++ b/packages/create-lz-oapp/src/index.tsx @@ -6,30 +6,51 @@ import { ConfigSummary } from "@/components/config"; import { Setup } from "@/components/setup"; import { promptToContinue } from "@layerzerolabs/io-devtools"; import { printLogo } from "@layerzerolabs/io-devtools/swag"; +import { version } from "../package.json"; +import { + ciOption, + destinationOption, + exampleOption, + packageManagerOption, +} from "./options"; +import type { Config, Example, PackageManager } from "./types"; +import { DefaultErrorMessage } from "./components/error"; interface Args { - version?: boolean; + ci?: boolean; + destination?: string; + example?: Example; + packageManager: PackageManager; } new Command("create-lz-oapp") .description("Create LayerZero OApp with one command") - .option("-v,--version", "Output version information", false) - .action(async ({ version }: Args) => { - // If the user only asked for a version, we'll print that out and exit - if (version === true) { - const pkg = await import("../package.json"); - - return console.log(pkg.version); - } - + .version(version) + .addOption(ciOption) + .addOption(destinationOption) + .addOption(exampleOption) + .addOption(packageManagerOption) + .action(async (args: Args) => { printLogo(); - // First we get the config from the user - const config = await promptForConfig(); + // We'll provide a CI mode - a non-interctaive mode in which all input is taken + // from the CLI arguments and if something is missing, an error is thrown + const { ci } = args; + + // First we get the config + const config = ci + ? // In CI mode, we'll validate what we got from the arguments + ensureConfigForCIMode(args) + : // In interactive mode we'll ask for the config, using the arguments as defaults + await promptForConfig(args); render().unmount(); - // Then we confirm we want to do this after showing the user what they have specified - const continuePlease = await promptToContinue(); + // Then we confirm with the user + const continuePlease = ci + ? // In CI mode we continue automatically, no questions asked + true + : // In interactive mode we'll confirm with the user + await promptToContinue(); if (!continuePlease) { return; } @@ -40,4 +61,59 @@ new Command("create-lz-oapp") // And wait for it to exit await setup.waitUntilExit(); }) + .configureOutput({ + outputError: handleError, + }) .parseAsync(); + +/** + * Helper utility for pretty printing any erros we might encounter + * + * @param {unknown} error + */ +function handleError(error: unknown) { + if (error instanceof Error) { + render().unmount(); + } else { + render().unmount(); + } +} + +/** + * Helper utility that will ensure that all the required CLI arguments + * are present in CI mode + * + * @param {Partial} config Config coming from the CLI arguments + * @returns {Config} config + */ +function ensureConfigForCIMode({ + destination, + example, + packageManager, +}: Partial): Config { + if (destination == null) { + render( + , + ).unmount(); + + process.exit(1); + } + + if (example == null) { + render( + , + ).unmount(); + + process.exit(1); + } + + if (packageManager == null) { + render( + , + ).unmount(); + + process.exit(1); + } + + return { destination, example, packageManager }; +} diff --git a/packages/create-lz-oapp/src/options.ts b/packages/create-lz-oapp/src/options.ts new file mode 100644 index 000000000..fa4784f83 --- /dev/null +++ b/packages/create-lz-oapp/src/options.ts @@ -0,0 +1,40 @@ +import { InvalidOptionArgumentError, Option } from 'commander' +import { AVAILABLE_PACKAGE_MANAGERS, EXAMPLES } from './config' +import { isDirectory, isFile } from '@layerzerolabs/io-devtools' +import { resolve } from 'path' + +export const packageManagerOption = new Option('-p,--package-manager ', 'Node package manager to use') + .choices(AVAILABLE_PACKAGE_MANAGERS.map(({ id }) => id)) + .argParser((id) => { + const manager = AVAILABLE_PACKAGE_MANAGERS.find((p) => p.id === id) + if (manager == null) { + throw new InvalidOptionArgumentError(`Package manager ${id} not found`) + } + + return manager + }) + +export const exampleOption = new Option('-e,--example ', 'Example project') + .choices(EXAMPLES.map(({ id }) => id)) + .argParser((id) => { + const example = EXAMPLES.find((e) => e.id === id) + if (example == null) { + throw new InvalidOptionArgumentError(`Example ${id} not found`) + } + + return example + }) + +export const destinationOption = new Option('-d,--destination ', 'Project directory').argParser((destination) => { + if (isDirectory(destination)) { + throw new InvalidOptionArgumentError(`Directory '${resolve(destination)}' already exists`) + } + + if (isFile(destination)) { + throw new InvalidOptionArgumentError(`File '${resolve(destination)}' already exists`) + } + + return destination +}) + +export const ciOption = new Option('--ci', 'Run in CI (non-interactive) mode').default(false) diff --git a/packages/create-lz-oapp/src/types.ts b/packages/create-lz-oapp/src/types.ts index 425518acf..2721d99d1 100644 --- a/packages/create-lz-oapp/src/types.ts +++ b/packages/create-lz-oapp/src/types.ts @@ -13,6 +13,8 @@ export interface Example { } export interface PackageManager { - command: string + id: string + executable: string + args: string[] label: string } diff --git a/packages/create-lz-oapp/src/utilities/installation.ts b/packages/create-lz-oapp/src/utilities/installation.ts index 219f22569..bc64cd861 100644 --- a/packages/create-lz-oapp/src/utilities/installation.ts +++ b/packages/create-lz-oapp/src/utilities/installation.ts @@ -7,7 +7,7 @@ export const installDependencies = (config: Config) => /** * Spawn the installation process. */ - const child = spawn(config.packageManager.command, ['install'], { + const child = spawn(config.packageManager.executable, config.packageManager.args, { cwd: config.destination, env: { ...process.env, @@ -30,5 +30,5 @@ export const installDependencies = (config: Config) => }) }) -export const isPackageManagerAvailable = ({ command }: PackageManager): boolean => - !!which.sync(command, { nothrow: true }) +export const isPackageManagerAvailable = ({ executable }: PackageManager): boolean => + !!which.sync(executable, { nothrow: true }) diff --git a/packages/create-lz-oapp/src/utilities/prompts.ts b/packages/create-lz-oapp/src/utilities/prompts.ts index 2b703d850..cf12d75c9 100644 --- a/packages/create-lz-oapp/src/utilities/prompts.ts +++ b/packages/create-lz-oapp/src/utilities/prompts.ts @@ -1,34 +1,58 @@ -import { EXAMPLES, PACKAGE_MANAGERS } from '@/config' -import prompts from 'prompts' -import { isPackageManagerAvailable } from './installation' -import { handlePromptState, isDirectory } from '@layerzerolabs/io-devtools' +import { EXAMPLES, AVAILABLE_PACKAGE_MANAGERS } from '@/config' +import prompts, { type Choice } from 'prompts' +import { handlePromptState, isDirectory, isFile } from '@layerzerolabs/io-devtools' import { resolve } from 'path' +import type { Config } from '@/types' -export const promptForConfig = () => - prompts([ +export const promptForConfig = (config: Partial = {}): Promise => { + return prompts([ { onState: handlePromptState, type: 'text', name: 'destination', message: 'Where do you want to start your project?', - initial: './my-lz-oapp', - validate: (path: string) => (isDirectory(path) ? `Directory '${resolve(path)}' already exists` : true), + initial: config.destination ?? './my-lz-oapp', + validate: (path: string) => + isDirectory(path) + ? `Directory '${resolve(path)}' already exists` + : isFile(path) + ? `File '${resolve(path)}' already exists` + : true, }, { onState: handlePromptState, type: 'select', name: 'example', message: 'Which example would you like to use as a starting point?', - choices: EXAMPLES.map((example) => ({ title: example.label, value: example })), + choices: EXAMPLES.map((example) => ({ + title: example.label, + value: example, + selected: example.id === config.example?.id, + })).sort(sortBySelected), }, { onState: handlePromptState, type: 'select', name: 'packageManager', - choices: PACKAGE_MANAGERS.filter(isPackageManagerAvailable).map((packageManager) => ({ + choices: AVAILABLE_PACKAGE_MANAGERS.map((packageManager) => ({ title: packageManager.label, value: packageManager, - })), + selected: packageManager.id === config.packageManager?.id, + })).sort(sortBySelected), message: 'What package manager would you like to use in your project?', }, ]) +} + +/** + * prompts has a weird issue where even if the selected property is set + * on a particular choice, it will not preselect it - instead, the first choice will be selected. + * + * To remedy this, we'll sort the choices and put the selected one first, + * mimicking the behavior of preselection + * + * @param {Choice} a + * @param {Choice} b + * @returns {number} + */ +const sortBySelected = (a: Choice, b: Choice): number => Number(b.selected) - Number(a.selected) diff --git a/packages/toolbox-foundry/package.json b/packages/toolbox-foundry/package.json index 739e70c0f..fc785a9e0 100644 --- a/packages/toolbox-foundry/package.json +++ b/packages/toolbox-foundry/package.json @@ -9,13 +9,7 @@ }, "license": "MIT", "files": [ - "lib", - "!lib/ds-test/.github", - "!lib/ds-test/.gitignore", - "!lib/ds-test/demo", - "!lib/forge-std/.github", - "!lib/forge-std/.gitignore", - "!lib/forge-std/.gitmodules" + "lib" ], "scripts": { "build": "make lib", diff --git a/tests-user/create-lz-oapp.sh b/tests-user/create-lz-oapp.sh deleted file mode 100755 index 89aa6b3ca..000000000 --- a/tests-user/create-lz-oapp.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/bash - -# This is a PoC test for create-lz-oapp -echo "Checking version of create-lz-oapp" -npx --yes create-lz-oapp --version \ No newline at end of file diff --git a/tests-user/lib/bats-assert b/tests-user/lib/bats-assert new file mode 160000 index 000000000..e2d855bc7 --- /dev/null +++ b/tests-user/lib/bats-assert @@ -0,0 +1 @@ +Subproject commit e2d855bc78619ee15b0c702b5c30fb074101159f diff --git a/tests-user/lib/bats-core b/tests-user/lib/bats-core new file mode 160000 index 000000000..3d3f63d97 --- /dev/null +++ b/tests-user/lib/bats-core @@ -0,0 +1 @@ +Subproject commit 3d3f63d9772b98c88586ec0a66bd358a85d9b4a6 diff --git a/tests-user/lib/bats-support b/tests-user/lib/bats-support new file mode 160000 index 000000000..9bf10e876 --- /dev/null +++ b/tests-user/lib/bats-support @@ -0,0 +1 @@ +Subproject commit 9bf10e876dd6b624fe44423f0b35e064225f7556 diff --git a/tests-user/ssh/README.md b/tests-user/ssh/README.md new file mode 100644 index 000000000..8217477d5 --- /dev/null +++ b/tests-user/ssh/README.md @@ -0,0 +1,6 @@ +To avoid manually needing to verify known hosts when connecting to GitHub in our user tests +(see `docker-compose.registry.yaml`) we add public key fingerprints to our known hosts. + +These should only be used in the user tests. + +See [GitHub Docs](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/githubs-ssh-key-fingerprints) for more information. \ No newline at end of file diff --git a/tests-user/ssh/known_hosts b/tests-user/ssh/known_hosts new file mode 100644 index 000000000..1c44994f6 --- /dev/null +++ b/tests-user/ssh/known_hosts @@ -0,0 +1,3 @@ +github.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GKJl +github.com ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBEmKSENjQEezOmxkZMy7opKgwFB9nkt5YRrYMjNuG5N87uRgg6CLrbo5wAdT/y6v0mKV0U2w0WZ2YB/++Tpockg= +github.com ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCj7ndNxQowgcQnjshcLrqPEiiphnt+VTTvDP6mHBL9j1aNUkY4Ue1gvwnGLVlOhGeYrnZaMgRK6+PKCUXaDbC7qtbW8gIkhL7aGCsOr/C56SJMy/BCZfxd1nWzAOxSDPgVsmerOBYfNqltV9/hWCqBywINIR+5dIg6JTJ72pcEpEjcYgXkE2YEFXV1JHnsKgbLWNlhScqb2UmyRkQyytRLtL+38TGxkxCflmO+5Z8CSSNY7GidjMIZ7Q4zMjA2n1nGrlTDkzwDCsw+wqFPGQA179cnfGWOWRVruj16z6XyvxvjJwbz0wQZ75XK5tKSb7FNyeIEs4TT4jk+S4dhPeAUC5y+bDYirYgM4GC7uEnztnZyaVWQ7B381AK4Qdrwt51ZqExKbQpTUNn+EjqoTwvqNj4kqx5QUCI0ThS/YkOxJCXmPUWZbhjpCg56i+2aB6CmK2JGhn57K5mj0MNdBXA4/WnwH6XoPWJzK5Nyu2zB3nAZp+S5hpQs+p1vN1/wsjk= \ No newline at end of file diff --git a/tests-user/tests/create-lz-oapp.bats b/tests-user/tests/create-lz-oapp.bats new file mode 100644 index 000000000..41266c1af --- /dev/null +++ b/tests-user/tests/create-lz-oapp.bats @@ -0,0 +1,144 @@ + + +# We'll setup an empty testing directory for this script and store its location in this variable +PROJECTS_DIRECTORY= + +# This will be run at the start of this testing suite, +# similar to beforeAll() in jest +setup() { + # Load bats-assert and bats-support + load "../lib/bats-support/load.bash" + load "../lib/bats-assert/load.bash" + + # For debugging purposes, we'll output the environment variables + # that influence the behavior of create-lz-oapp + echo "create-lz-oapp:repository $LAYERZERO_EXAMPLES_REPOSITORY_URL" 1>&2 + echo "create-lz-oapp:ref $LAYERZERO_EXAMPLES_REPOSITORY_REF" 1>&2 + + # Setup a directory for all the projects created by this test + PROJECTS_DIRECTORY=$(mktemp -d) +} + +teardown() { + rm -rf "$PROJECTS_DIRECTORY" +} + +@test "should output version" { + npx --yes create-lz-oapp --version +} + +@test "should fail if --destination is missing in CI mode" { + run npx --yes create-lz-oapp --ci --example oft + + assert_failure + assert_output --partial "Missing argument: --destination must be specified in CI mode" +} + +@test "should fail if --destination directory already exists in CI mode" { + local DESTINATION="$PROJECTS_DIRECTORY/existing" + mkdir -p "$DESTINATION" + + run npx --yes create-lz-oapp --ci --example oft --destination $DESTINATION + + assert_failure + assert_output --regexp "Directory '.*?' already exists" +} + +@test "should fail if --destination is an existing file in CI mode" { + local DESTINATION="$PROJECTS_DIRECTORY/file.json" + touch $DESTINATION + + run npx --yes create-lz-oapp --ci --example oft --destination $DESTINATION + assert_failure + assert_output --regexp "File '.*?' already exists" +} + +@test "should fail if --example is missing in CI mode" { + local DESTINATION="$PROJECTS_DIRECTORY/unused" + + run npx --yes create-lz-oapp --ci --destination $DESTINATION + + assert_failure + assert_output --partial "Missing argument: --example must be specified in CI mode" + assert [ ! -d $DESTINATION ] +} + +@test "should fail if --example is not valid in CI mode" { + local DESTINATION="$PROJECTS_DIRECTORY/unused" + + run npx --yes create-lz-oapp --ci --destination $DESTINATION --example wat + + assert_failure + assert [ ! -d $DESTINATION ] +} + +@test "should fail if --package-manager is not valid in CI mode" { + local DESTINATION="$PROJECTS_DIRECTORY/unused" + + run npx --yes create-lz-oapp --ci --destination $DESTINATION --example oft --package-manager wroom + + assert_failure + assert_output --partial "manager wroom not found" + assert [ ! -d $DESTINATION ] +} + +@test "should work with pnpm & oapp example in CI mode" { + skip + local DESTINATION="$PROJECTS_DIRECTORY/pnpm-oapp" + + npx --yes create-lz-oapp --ci --example oapp --destination $DESTINATION --package-manager pnpm + assert_success + cd "$DESTINATION" + pnpm compile + pnpm test +} + +@test "should work with pnpm & oft example in CI mode" { + skip + local DESTINATION="$PROJECTS_DIRECTORY/pnpm-oft" + + npx --yes create-lz-oapp --ci --example oft --destination $DESTINATION --package-manager pnpm + cd "$DESTINATION" + pnpm compile + pnpm test +} + +@test "should work with yarn & oapp example in CI mode" { + skip + local DESTINATION="$PROJECTS_DIRECTORY/yarn-oapp" + + npx --yes create-lz-oapp --ci --example oapp --destination $DESTINATION --package-manager yarn + cd "$DESTINATION" + yarn compile + yarn test +} + +@test "should work with yarn & oft example in CI mode" { + skip + local DESTINATION="$PROJECTS_DIRECTORY/yarn-oft" + + npx --yes create-lz-oapp --ci --example oft --destination $DESTINATION --package-manager yarn + cd "$DESTINATION" + yarn compile + yarn test +} + +@test "should work with npm & oapp example in CI mode" { + skip + local DESTINATION="$PROJECTS_DIRECTORY/npm-oapp" + + npx --yes create-lz-oapp --ci --example oapp --destination $DESTINATION --package-manager npm + cd "$DESTINATION" + npm run compile + npm run test +} + +@test "should work with npm & oft example in CI mode" { + skip + local DESTINATION="$PROJECTS_DIRECTORY/npm-oft" + + npx --yes create-lz-oapp --ci --example oft --destination $DESTINATION --package-manager npm + cd "$DESTINATION" + npm run compile + npm run test +} \ No newline at end of file