mirror of
https://github.com/tauri-apps/tauri.git
synced 2024-11-28 03:47:37 +03:00
convert jest tests to child_process run script (#2308)
* convert jest tests to child_process run script * remove vuecli (it freezes), add angular * run cargo build in correct dir * add in asserts on fs * normalize assert for node14 * fix installing empty dependencies * add messages to asserts * use test dir to check if running local cli * try running in parallel * run in parallel and log output serially * avoid parallel, skip yarn for now * add change file * disable running with npm6 due to vite fail Co-authored-by: amrbashir <48618675+amrbashir@users.noreply.github.com>
This commit is contained in:
parent
63ad303903
commit
c410e034f7
6
.changes/cta-test-script.md
Normal file
6
.changes/cta-test-script.md
Normal file
@ -0,0 +1,6 @@
|
||||
---
|
||||
"create-tauri-app": patch
|
||||
"cli.js": patch
|
||||
---
|
||||
|
||||
Adjust check for `dev` mode and switch CTA test to a script runner. The script gives us more control and better output into any failures.
|
74
.github/workflows/test-cta.yml
vendored
74
.github/workflows/test-cta.yml
vendored
@ -3,6 +3,9 @@
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
name: test create-tauri-app
|
||||
env:
|
||||
RUST_BACKTRACE: 1
|
||||
TAURI_RECIPE: 'vanillajs,cra,vite,ngcli'
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
@ -13,20 +16,16 @@ on:
|
||||
paths:
|
||||
- "tooling/create-tauri-app/**"
|
||||
|
||||
env:
|
||||
RUST_BACKTRACE: 1
|
||||
|
||||
jobs:
|
||||
create-recipe-with-npm:
|
||||
name: "node@${{ matrix.node }} + npm@${{ matrix.manager }}: ${{ matrix.recipe }}"
|
||||
name: "node@${{ matrix.node }} + npm@${{ matrix.manager }}"
|
||||
runs-on: ${{ github.event.inputs.platform || 'ubuntu' }}-latest
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
node: ["14", "16"]
|
||||
manager: ["6", "7"]
|
||||
recipe: ["vanillajs", "cra", "vite", "ngcli", "svelte", "dominator"]
|
||||
manager: ["7"]
|
||||
exclude:
|
||||
- node: "16"
|
||||
manager: "6"
|
||||
@ -62,40 +61,37 @@ jobs:
|
||||
- run: yarn test
|
||||
working-directory: tooling/create-tauri-app
|
||||
env:
|
||||
TAURI_RECIPE: ${{ matrix.recipe }}
|
||||
TAURI_RUN_MANAGER: "npm"
|
||||
|
||||
create-recipe-with-yarn:
|
||||
name: "node@${{ matrix.node }} + yarn@1: ${{ matrix.recipe }}"
|
||||
runs-on: ${{ github.event.inputs.platform || 'ubuntu' }}-latest
|
||||
# create-recipe-with-yarn:
|
||||
# name: "node@${{ matrix.node }} + yarn@1"
|
||||
# runs-on: ${{ github.event.inputs.platform || 'ubuntu' }}-latest
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
node: ["14", "16"]
|
||||
recipe: ["vanillajs", "cra", "vite", "ngcli", "svelte"]
|
||||
# strategy:
|
||||
# fail-fast: false
|
||||
# matrix:
|
||||
# node: ["14", "16"]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: install stable
|
||||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
- uses: volta-cli/action@v1
|
||||
with:
|
||||
node-version: ${{ matrix.node }}
|
||||
yarn-version: 1.22.5
|
||||
- name: install webkit2gtk
|
||||
if: (github.event.inputs.platform || 'ubuntu') == 'ubuntu'
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y libgtk-3-dev libgtksourceview-3.0-dev webkit2gtk-4.0 libappindicator3-dev
|
||||
- run: yarn
|
||||
working-directory: tooling/create-tauri-app
|
||||
- run: yarn build
|
||||
working-directory: tooling/create-tauri-app
|
||||
- run: yarn test
|
||||
working-directory: tooling/create-tauri-app
|
||||
env:
|
||||
TAURI_RECIPE: ${{ matrix.recipe }}
|
||||
TAURI_RUN_MANAGER: "yarn"
|
||||
# steps:
|
||||
# - uses: actions/checkout@v2
|
||||
# - name: install stable
|
||||
# uses: actions-rs/toolchain@v1
|
||||
# with:
|
||||
# toolchain: stable
|
||||
# - uses: volta-cli/action@v1
|
||||
# with:
|
||||
# node-version: ${{ matrix.node }}
|
||||
# yarn-version: 1.22.5
|
||||
# - name: install webkit2gtk
|
||||
# if: (github.event.inputs.platform || 'ubuntu') == 'ubuntu'
|
||||
# run: |
|
||||
# sudo apt-get update
|
||||
# sudo apt-get install -y libgtk-3-dev libgtksourceview-3.0-dev webkit2gtk-4.0 libappindicator3-dev
|
||||
# - run: yarn
|
||||
# working-directory: tooling/create-tauri-app
|
||||
# - run: yarn build
|
||||
# working-directory: tooling/create-tauri-app
|
||||
# - run: yarn test
|
||||
# working-directory: tooling/create-tauri-app
|
||||
# env:
|
||||
# TAURI_RUN_MANAGER: "yarn"
|
||||
|
@ -57,8 +57,8 @@ export async function runOnRustCli(
|
||||
onClose
|
||||
)
|
||||
} else {
|
||||
if (existsSync(resolve(targetPath, '../bundler'))) {
|
||||
// running local CLI
|
||||
if (existsSync(resolve(targetPath, 'test'))) {
|
||||
// running local CLI since test directory exists
|
||||
const cliPath = resolve(targetPath, '../cli.rs')
|
||||
spawnSync('cargo', ['build', '--release'], cliPath)
|
||||
const localCliPath = resolve(
|
||||
|
@ -29,7 +29,7 @@
|
||||
"lint:lockfile": "lockfile-lint --path yarn.lock --type yarn --validate-https --allowed-hosts npm yarn",
|
||||
"format": "prettier --write --end-of-line=auto \"./**/*.{cjs,js,jsx,ts,tsx,html,css,json}\" --ignore-path .gitignore",
|
||||
"format:check": "prettier --check --end-of-line=auto \"./**/*.{cjs,js,jsx,ts,tsx,html,css,json}\" --ignore-path .gitignore",
|
||||
"test": "jest --runInBand"
|
||||
"test": "node ./test/spawn.test.mjs"
|
||||
},
|
||||
"dependencies": {
|
||||
"chalk": "4.1.1",
|
||||
@ -39,16 +39,17 @@
|
||||
"scaffe": "1.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@effection/process": "2.0.0-beta.8",
|
||||
"@rollup/plugin-commonjs": "19.0.0",
|
||||
"@rollup/plugin-node-resolve": "13.0.0",
|
||||
"@rollup/plugin-typescript": "8.2.1",
|
||||
"@types/cross-spawn": "6.0.2",
|
||||
"@types/inquirer": "7.3.1",
|
||||
"@types/jest": "26.0.23",
|
||||
"@types/minimist": "1.2.1",
|
||||
"@types/semver": "7.3.6",
|
||||
"@typescript-eslint/eslint-plugin": "4.25.0",
|
||||
"@typescript-eslint/parser": "4.25.0",
|
||||
"effection": "2.0.0-beta.8",
|
||||
"eslint": "7.27.0",
|
||||
"eslint-config-prettier": "8.3.0",
|
||||
"eslint-config-standard-with-typescript": "20.0.0",
|
||||
@ -57,11 +58,9 @@
|
||||
"eslint-plugin-node": "11.1.0",
|
||||
"eslint-plugin-promise": "5.1.0",
|
||||
"eslint-plugin-security": "1.4.0",
|
||||
"fixturez": "1.1.0",
|
||||
"jest": "27.0.3",
|
||||
"prettier": "2.3.0",
|
||||
"rollup": "2.50.4",
|
||||
"ts-jest": "27.0.1",
|
||||
"temp-dir": "^2.0.0",
|
||||
"tslib": "2.2.0",
|
||||
"typescript": "4.3.2"
|
||||
}
|
||||
|
@ -368,7 +368,7 @@ const runInit = async (argv: Argv): Promise<void> => {
|
||||
logStep(`Updating ${reset(yellow('"package.json"'))}`)
|
||||
updatePackageJson(appDirectory, appName)
|
||||
|
||||
logStep(`Running: ${reset(yellow('tauri init'))}`)
|
||||
logStep(`Running ${reset(yellow('"tauri init"'))}`)
|
||||
const binary = !argv.b ? packageManager : resolve(appDirectory, argv.b)
|
||||
// pnpm is equivalent to yarn and can run srcipts without using "run" but due to this bug https://github.com/pnpm/pnpm/issues/2764
|
||||
// we need to pass "--" to pnpm or arguments won't be parsed correctly so for this command only we are gonna treat pnpm as npm equivalent/
|
||||
|
@ -1,169 +0,0 @@
|
||||
// Copyright 2019-2021 Tauri Programme within The Commons Conservancy
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
import execa from 'execa'
|
||||
import fixtures from 'fixturez'
|
||||
const f = fixtures(__dirname)
|
||||
import path from 'path'
|
||||
import fs from 'fs'
|
||||
|
||||
const ctaBinary = path.resolve('./bin/create-tauri-app.js')
|
||||
const clijs = path.resolve('../cli.js/')
|
||||
const api = path.resolve('../api/')
|
||||
|
||||
const manager = process.env.TAURI_RUN_MANAGER ?? 'npm'
|
||||
const recipes = process.env.TAURI_RECIPE
|
||||
? [process.env.TAURI_RECIPE]
|
||||
: ['vanillajs', 'cra', 'vite', 'vuecli', 'ngcli', 'svelte', 'dominator']
|
||||
const timeoutLong = 900000
|
||||
const timeoutLittleLonger = 930000
|
||||
const logOut = false ? 'inherit' : 'pipe'
|
||||
|
||||
describe('CTA', () => {
|
||||
console.warn(
|
||||
'NOTE: You need to have installed and built cli.js and api before running the tests.'
|
||||
)
|
||||
describe.each(recipes.map((recipe) => [recipe, 'tauri-app']))(
|
||||
`%s recipe`,
|
||||
(recipe: string, appName: string) => {
|
||||
it(
|
||||
'runs',
|
||||
async () => {
|
||||
// creates a temp folder to run CTA within (this is our cwd)
|
||||
const folder = f.temp()
|
||||
const appFolder = path.join(folder, appName)
|
||||
|
||||
// runs CTA with all args set to avoid any prompts
|
||||
const cta = await execa(
|
||||
'node',
|
||||
[
|
||||
ctaBinary,
|
||||
'--manager',
|
||||
manager,
|
||||
'--recipe',
|
||||
recipe,
|
||||
'--ci',
|
||||
'--dev'
|
||||
],
|
||||
{
|
||||
all: true,
|
||||
stdio: logOut,
|
||||
cwd: folder,
|
||||
timeout: timeoutLong
|
||||
}
|
||||
)
|
||||
|
||||
// check to make certain it didn't fail anywhere
|
||||
expect(cta.failed).toBe(false)
|
||||
expect(cta.timedOut).toBe(false)
|
||||
expect(cta.isCanceled).toBe(false)
|
||||
expect(cta.killed).toBe(false)
|
||||
expect(cta.signal).toBe(undefined)
|
||||
|
||||
const packageFileInitial: {
|
||||
[k: string]: string | object
|
||||
} = JSON.parse(
|
||||
await fs.promises.readFile(
|
||||
path.join(appFolder, 'package.json'),
|
||||
'utf-8'
|
||||
)
|
||||
)
|
||||
expect(packageFileInitial['name']).toBe(appName)
|
||||
|
||||
// run a tauri build to check if what we produced
|
||||
// can actually create an app
|
||||
// TODO long term we will want to hook this up to a real test harness
|
||||
// and then run that test suite instead
|
||||
let opts: string[] = []
|
||||
if (manager === 'npm') {
|
||||
opts =
|
||||
recipe == 'vuecli'
|
||||
? ['run', 'tauri:build']
|
||||
: ['run', 'tauri', '--', 'build']
|
||||
} else if (manager === 'yarn') {
|
||||
opts = recipe == 'vuecli' ? ['tauri:build'] : ['tauri', 'build']
|
||||
}
|
||||
const tauriBuild = await execa(manager, opts, {
|
||||
all: true,
|
||||
stdio: logOut,
|
||||
cwd: appFolder,
|
||||
timeout: timeoutLong
|
||||
})
|
||||
|
||||
expect(tauriBuild.failed).toBe(false)
|
||||
expect(tauriBuild.timedOut).toBe(false)
|
||||
expect(tauriBuild.isCanceled).toBe(false)
|
||||
expect(tauriBuild.killed).toBe(false)
|
||||
expect(tauriBuild.signal).toBe(undefined)
|
||||
|
||||
const packageFileOutput: {
|
||||
[k: string]: string | object
|
||||
} = JSON.parse(
|
||||
await fs.promises.readFile(
|
||||
path.join(appFolder, 'package.json'),
|
||||
'utf-8'
|
||||
)
|
||||
)
|
||||
expect(packageFileOutput['name']).toBe(appName)
|
||||
|
||||
const assertCustom: { [k: string]: Function } = {
|
||||
vanillajs: () => {
|
||||
expect(packageFileOutput['scripts']).toMatchObject({
|
||||
tauri: 'tauri'
|
||||
})
|
||||
},
|
||||
cra: () => {
|
||||
expect(packageFileOutput['scripts']).toEqual(
|
||||
expect.objectContaining({
|
||||
tauri: 'tauri'
|
||||
})
|
||||
)
|
||||
},
|
||||
vite: () => {
|
||||
expect(packageFileOutput['scripts']).toEqual(
|
||||
expect.objectContaining({
|
||||
tauri: 'tauri'
|
||||
})
|
||||
)
|
||||
},
|
||||
vuecli: () => {
|
||||
expect(packageFileOutput['scripts']).toEqual(
|
||||
expect.objectContaining({
|
||||
'tauri:build': expect.anything(),
|
||||
'tauri:serve': expect.anything()
|
||||
})
|
||||
)
|
||||
},
|
||||
ngcli: () => {
|
||||
expect(packageFileOutput['scripts']).toEqual(
|
||||
expect.objectContaining({
|
||||
ng: 'ng',
|
||||
tauri: 'tauri'
|
||||
})
|
||||
)
|
||||
},
|
||||
svelte: () => {
|
||||
expect(packageFileOutput['scripts']).toEqual(
|
||||
expect.objectContaining({
|
||||
tauri: 'tauri'
|
||||
})
|
||||
)
|
||||
},
|
||||
dominator: () => {
|
||||
expect(packageFileOutput['scripts']).toEqual(
|
||||
expect.objectContaining({
|
||||
tauri: 'tauri'
|
||||
})
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const getCustomAsserts = assertCustom[recipe]
|
||||
if (getCustomAsserts) getCustomAsserts()
|
||||
},
|
||||
timeoutLittleLonger
|
||||
)
|
||||
}
|
||||
)
|
||||
})
|
194
tooling/create-tauri-app/test/spawn.test.mjs
Normal file
194
tooling/create-tauri-app/test/spawn.test.mjs
Normal file
@ -0,0 +1,194 @@
|
||||
// Copyright 2019-2021 Tauri Programme within The Commons Conservancy
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
import { main, spawn, sleep } from 'effection'
|
||||
import { exec } from '@effection/process'
|
||||
import fs from 'fs/promises'
|
||||
import path from 'path'
|
||||
import crypto from 'crypto'
|
||||
import tempDirectory from 'temp-dir'
|
||||
|
||||
let assert
|
||||
const nodeVersion = process.versions.node.split('.')[0]
|
||||
if (nodeVersion === '14') {
|
||||
assert = await import('assert')
|
||||
} else {
|
||||
assert = await import('assert/strict')
|
||||
}
|
||||
|
||||
const ctaBinary = path.resolve('./bin/create-tauri-app.js')
|
||||
const clijs = path.resolve('../cli.js/')
|
||||
const api = path.resolve('../api/')
|
||||
|
||||
const manager = process.env.TAURI_RUN_MANAGER || 'yarn'
|
||||
const recipes = process.env.TAURI_RECIPE
|
||||
? process.env.TAURI_RECIPE.split(',')
|
||||
: ['vanillajs', 'cra', 'vite', 'ngcli']
|
||||
const parallelize = process.env.TAURI_RECIPE_PARALLELIZE || false
|
||||
|
||||
main(function* start() {
|
||||
const tauriTemp = path.join(
|
||||
tempDirectory,
|
||||
`tauri_${crypto.randomBytes(16).toString('hex')}`
|
||||
)
|
||||
|
||||
try {
|
||||
const appName = 'tauri-app'
|
||||
let output = {}
|
||||
for (let i = 0; i < recipes.length; i++) {
|
||||
const recipe = recipes[i]
|
||||
console.log(`::group::recipe ${recipe}`)
|
||||
console.log(`------------------ ${recipe} started -------------------`)
|
||||
const recipeFolder = path.join(tauriTemp, recipe)
|
||||
const appFolder = path.join(recipeFolder, appName)
|
||||
yield fs.mkdir(recipeFolder, { recursive: true })
|
||||
console.log(`${recipeFolder} created.`)
|
||||
|
||||
// runs CTA with all args set to avoid any prompts
|
||||
const run = `node '${ctaBinary}' --manager ${manager} --recipe ${recipe} --ci --dev`
|
||||
console.log(`[running] ${run}`)
|
||||
|
||||
let opts = []
|
||||
if (manager === 'npm') {
|
||||
opts =
|
||||
recipe == 'vuecli'
|
||||
? ['run', 'tauri:build']
|
||||
: ['run', 'tauri', '--', 'build']
|
||||
} else if (manager === 'yarn') {
|
||||
opts = recipe == 'vuecli' ? ['tauri:build'] : ['tauri', 'build']
|
||||
}
|
||||
|
||||
if (!parallelize) {
|
||||
const cta = yield exec(run, { cwd: recipeFolder })
|
||||
yield streamLogs(cta)
|
||||
// now it is finished, assert on some things
|
||||
yield assertCTAState({ appFolder, appName })
|
||||
|
||||
const tauriBuild = yield exec(manager, {
|
||||
arguments: opts,
|
||||
cwd: appFolder
|
||||
})
|
||||
yield streamLogs(tauriBuild)
|
||||
// build is complete, assert on some things
|
||||
yield assertTauriBuildState({ appFolder, appName })
|
||||
} else {
|
||||
console.log('running CTA recipe in parallel')
|
||||
output[recipe] = yield spawn(function* () {
|
||||
const childCTA = yield exec(run, { cwd: recipeFolder })
|
||||
const cta = yield captureLogs(childCTA)
|
||||
const childTauriBuild = yield exec(manager, {
|
||||
arguments: opts,
|
||||
cwd: appFolder
|
||||
})
|
||||
const tauriBuild = yield captureLogs(childTauriBuild)
|
||||
return { cta, tauriBuild }
|
||||
})
|
||||
}
|
||||
|
||||
console.log(`------------------ ${recipe} complete -------------------`)
|
||||
console.log('::endgroup::')
|
||||
// sometimes it takes a moment to flush all of the logs
|
||||
// to the console, let things catch up here
|
||||
yield sleep(1000)
|
||||
}
|
||||
|
||||
if (parallelize) {
|
||||
for (let i = 0; i < recipes.length; i++) {
|
||||
const recipe = recipes[i]
|
||||
console.log(`::group::recipe ${recipe} logs`)
|
||||
console.log(
|
||||
`------------------ ${recipe} output start -------------------`
|
||||
)
|
||||
const out = yield output[recipe]
|
||||
console.log(out.cta)
|
||||
console.log(out.tauriBuild)
|
||||
console.log(
|
||||
`------------------ ${recipe} output end -------------------`
|
||||
)
|
||||
console.log('::endgroup::')
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
throw Error(e)
|
||||
} finally {
|
||||
console.log('\nstopping process...')
|
||||
// wait a tick for file locks to be release
|
||||
yield sleep(5000)
|
||||
yield fs.rm(tauriTemp, { recursive: true, force: true })
|
||||
console.log(`${tauriTemp} deleted.`)
|
||||
}
|
||||
})
|
||||
|
||||
function* streamLogs(child) {
|
||||
yield child.stdout.forEach((data) => {
|
||||
process.stdout.write(data)
|
||||
})
|
||||
yield child.stderr.forEach((data) => {
|
||||
process.stderr.write(data)
|
||||
})
|
||||
}
|
||||
|
||||
function* captureLogs(child) {
|
||||
let log = ''
|
||||
yield child.stdout.forEach((data) => {
|
||||
log += data
|
||||
})
|
||||
yield child.stderr.forEach((data) => {
|
||||
log += data
|
||||
})
|
||||
|
||||
return log
|
||||
}
|
||||
|
||||
function* assertCTAState({ appFolder, appName }) {
|
||||
const packageFileInitial = JSON.parse(
|
||||
yield fs.readFile(path.join(appFolder, 'package.json'), 'utf-8')
|
||||
)
|
||||
assert.strictEqual(
|
||||
packageFileInitial.name,
|
||||
appName,
|
||||
`The package.json did not have the name "${appName}".`
|
||||
)
|
||||
assert.strictEqual(
|
||||
packageFileInitial.scripts.tauri,
|
||||
'tauri',
|
||||
`The package.json did not have the tauri script.`
|
||||
)
|
||||
}
|
||||
|
||||
function* assertTauriBuildState({ appFolder, appName }) {
|
||||
const packageFileOutput = JSON.parse(
|
||||
yield fs.readFile(path.join(appFolder, 'package.json'), 'utf-8')
|
||||
)
|
||||
assert.strictEqual(
|
||||
packageFileOutput.name,
|
||||
appName,
|
||||
`The package.json did not have the name "${appName}".`
|
||||
)
|
||||
assert.strictEqual(
|
||||
packageFileOutput.scripts.tauri,
|
||||
'tauri',
|
||||
`The package.json did not have the tauri script.`
|
||||
)
|
||||
|
||||
const cargoFileOutput = yield fs.readFile(
|
||||
path.join(appFolder, 'src-tauri', 'Cargo.toml'),
|
||||
'utf-8'
|
||||
)
|
||||
assert.strictEqual(
|
||||
cargoFileOutput.startsWith(`[package]\nname = "app"`),
|
||||
true,
|
||||
`The Cargo.toml did not have the name "app".`
|
||||
)
|
||||
|
||||
const tauriTarget = yield fs.readdir(
|
||||
path.join(appFolder, 'src-tauri', 'target')
|
||||
)
|
||||
assert.strictEqual(
|
||||
tauriTarget.includes('release'),
|
||||
true,
|
||||
`The Tauri build does not have a target/release directory.`
|
||||
)
|
||||
}
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user