Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

create unit tests on main adoption script #2250

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion packages/utils/cli/src/scan/index.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ const DEFAULT_CONFIG = {
},
}

export async function adoption(options) {
export async function adoption(options = {}) {
let config = DEFAULT_CONFIG

const configFileRoute = path.join(process.cwd(), options.configuration || '.spark-ui.cjs')
Expand Down
51 changes: 51 additions & 0 deletions packages/utils/cli/src/scan/index.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import path from 'node:path'

import fse from 'fs-extra'
import { fileURLToPath } from 'url'
import { beforeEach, describe, expect, it } from 'vitest'

import cmd, { ENTER } from '../../test/utils/cmd'

const __dirname = fileURLToPath(import.meta.url)
const cliPath = path.join(__dirname, '../../../bin/spark.mjs')

const cliProcess = cmd.create(cliPath)

describe('CLI `spark scan`', () => {
const OUTPUT_FILE = 'report.json'

beforeEach(() => {
if (fse.existsSync(OUTPUT_FILE)) fse.removeSync(OUTPUT_FILE)
})

describe('Adoption (components adoption)', () => {
it('should execute command with default config', async () => {
const response = await cliProcess.execute(['scan', 'adoption'], [ENTER])

expect(response).toMatch(/Loading default configuration/i)
expect(response).toMatch(/Scanning adoption for @spark-ui/i)
expect(response).toMatch(/Found/i)

/**
* With no output option the adoption report will be simply logged
*/
expect(
response.filter(
(entry: string | Record<string, unknown>) =>
entry['@spark-ui/button' as keyof typeof entry]
)
).toBeDefined()
})

it('should write report to output file path', async () => {
const response = await cliProcess.execute(['scan', 'adoption', '-o', OUTPUT_FILE], [ENTER])

expect(response).toMatch(/Scanning adoption for @spark-ui/i)

expect(fse.pathExistsSync(OUTPUT_FILE)).toBe(true)
})
})
})

// Custom config
// Sorting option
4 changes: 2 additions & 2 deletions packages/utils/cli/test/spark-generate.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ describe('CLI `spark generate` (component package)', () => {
]

const assertExpectedFiles = (filePath: string) => {
expect(response).toContain(`Created ${packagePath}${filePath}`)
expect(response.toString()).toContain(`Created ${packagePath}${filePath}`)
expect(fse.pathExistsSync(`${packagePath}${filePath}`)).toBe(true)
}

Expand All @@ -61,7 +61,7 @@ describe('CLI `spark generate` (component package)', () => {
const packagePath = path.join(process.cwd(), 'packages', contextPath, packageName)

// THEN it throws an error and fails to create files for this package
expect(response).toContain(
expect(response.toString()).toContain(
'Name name must contain letters and dash symbols only (ex: "my-package")'
)
expect(fse.pathExistsSync(packagePath)).toBe(false)
Expand Down
53 changes: 36 additions & 17 deletions packages/utils/cli/test/utils/cmd.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,30 @@ import { constants } from 'os'

const PATH = process.env.PATH

/**
* Format CMD response as a JSON object
*/
function getReportFromData(data) {
const regex = /({[\s\S]*})/ // Regular expression to match object type
const match = data.match(regex)

const messages = data
.slice(0, match?.index ?? undefined)
.trim()
.split('\n')
.map(line => line.trim())
.filter(line => line)

const json = match ? JSON.parse(match[0]) : undefined

return [...messages, json]
}

/**
* Creates a child process with script path
* @param processPath Path of the process to execute
* @param args Arguments to the command
* @param env (optional) Environment variables
* @param {string} processPath Path of the process to execute
* @param {Array} args Arguments to the command
* @param {Object} env (optional) Environment variables
*/
function createProcess(processPath, args = [], env = null) {
// Ensure that path exists
Expand Down Expand Up @@ -44,18 +63,18 @@ function createProcess(processPath, args = [], env = null) {
* Creates a command and executes inputs (user responses) to the stdin
* Returns a promise that resolves when all inputs are sent
* Rejects the promise if any error
* @param processPath Path of the process to execute
* @param args Arguments to the command
* @param inputs (Optional) Array of inputs (user responses)
* @param opts (optional) Environment variables
* @param {string} processPath Path of the process to execute
* @param {Array} args Arguments to the command
* @param {Array} inputs (Optional) Array of inputs (user responses)
* @param {Object} opts (optional) Environment variables
*/
function executeWithInput(processPath, args, inputs, opts = {}) {
function executeWithInput(processPath, args = [], inputs = [], opts = {}) {
if (!Array.isArray(inputs)) {
opts = inputs
inputs = []
}

const { env = null, timeout = 100, maxTimeout = 10000 } = opts
const { env = null, timeout = 250, maxTimeout = 10000 } = opts
const childProcess = createProcess(processPath, args, env)
childProcess.stdin.setEncoding('utf-8')

Expand All @@ -64,12 +83,12 @@ function executeWithInput(processPath, args, inputs, opts = {}) {
// Creates a loop to feed user inputs to the child process in order to get results from the tool
// This code is heavily inspired (if not blantantly copied) from inquirer-test:
// https://github.com/ewnd9/inquirer-test/blob/6e2c40bbd39a061d3e52a8b1ee52cdac88f8d7f7/index.js#L14
const loop = ins => {
const loop = inputs => {
if (killIOTimeout) {
clearTimeout(killIOTimeout)
}

if (!ins.length) {
if (!inputs.length) {
childProcess.stdin.end()

// Set a timeout to wait for CLI response. If CLI takes longer than
Expand All @@ -83,12 +102,12 @@ function executeWithInput(processPath, args, inputs, opts = {}) {
}

currentInputTimeout = setTimeout(() => {
childProcess.stdin.write(ins[0])
childProcess.stdin.write(inputs[0])
// Log debug I/O statements on tests
if (env && env.DEBUG) {
console.log('input:', ins[0]) // eslint-disable-line no-console
console.log('input:', inputs[0])
}
loop(ins.slice(1))
loop(inputs.slice(1))
}, timeout)
}

Expand All @@ -97,15 +116,15 @@ function executeWithInput(processPath, args, inputs, opts = {}) {
childProcess.stderr.on('data', data => {
// Log debug I/O statements on tests
if (env && env.DEBUG) {
console.log('error:', data.toString()) // eslint-disable-line no-console
console.log('error:', data.toString())
}
})

// Get output from CLI
childProcess.stdout.on('data', data => {
// Log debug I/O statements on tests
if (env && env.DEBUG) {
console.log('output:', data.toString()) // eslint-disable-line no-console
console.log('output:', data.toString())
}
})

Expand All @@ -130,7 +149,7 @@ function executeWithInput(processPath, args, inputs, opts = {}) {
clearTimeout(killIOTimeout)
}

resolve(result.toString())
resolve(getReportFromData(result.toString()))
})
)
})
Expand Down
Loading