Skip to content
Merged
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: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -106,3 +106,5 @@ dist
.DS_Store
# build
index.cjs
# e2e test
electron-vite-test
167 changes: 167 additions & 0 deletions __tests__/e2e.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
import fs from 'node:fs'
import path from 'node:path'
import cp from 'node:child_process'
import {
type ElectronApplication,
type Page,
type JSHandle,
_electron as electron,
} from 'playwright'
import type { BrowserWindow } from 'electron'
import {
beforeAll,
afterAll,
describe,
expect,
test,
} from 'vitest'

const CLI_PATH = path.join(__dirname, '..')
const projectName = 'electron-vite-test'
const generatePath = path.join(CLI_PATH, projectName)
const pkgManager = process.platform === 'win32' ? 'npm.cmd' : 'npm'
let electronApp: ElectronApplication
let page: Page

if (process.platform === 'linux') {
// pass ubuntu
test(() => expect(true).true)
} else {
beforeAll(async () => {
fs.rmSync(generatePath, { recursive: true, force: true })

await createProject()

// enableElectronMirror()

const installLogs = execSync(`${pkgManager} install`)
writeFileSync('npm-install.log', installLogs)

const buildLogs = execSync('vite build')
writeFileSync('vite-build.log', buildLogs)

electronApp = await electron.launch({
args: ['.', '--no-sandbox'],
cwd: generatePath,
env: { ...process.env, NODE_ENV: 'development' },
})
page = await electronApp.firstWindow()

const mainWin: JSHandle<BrowserWindow> = await electronApp.browserWindow(page)
await mainWin.evaluate(async (win) => {
win.webContents.executeJavaScript('console.log("Execute JavaScript with e2e testing.")')
})
}, 1000 * 60 * 3)

afterAll(async () => {
await page.close()
await electronApp.close()
})

describe('[create-electron-vite] e2e tests', async () => {
test('startup', async () => {
console.log('[e2e] npm-install.log:\n', readFileSync('npm-install.log'))
console.log('[e2e] vite-build.log:\n', readFileSync('vite-build.log'))

const title = await page.title()
expect(title).eq('Vite + Vue + TS')
})

test('should be home page is load correctly', async () => {
const h1 = await page.$('h1')
const title = await h1?.textContent()
expect(title).eq('Vite + Vue')
})

test('should be count button can click', async () => {
const countButton = await page.$('button')
await countButton?.click()
const countValue = await countButton?.textContent()
expect(countValue).eq('count is 1')
})
})
}

async function createProject() {
return new Promise((resolve) => {
const child = cp.spawn('node', [CLI_PATH, projectName])

child.stdout.on('data', (chunk) => {
const stdout: string = chunk.toString()

if (stdout.includes('Project template:')) {
child.stdin.write('\n')
} else if (stdout.includes('Done. Now run:')) {
child.kill()
resolve(projectName)
}
})
})
}

// For local testing
function enableElectronMirror() {
let npmrcContent = readFileSync('.npmrc')

npmrcContent = npmrcContent
.split('\n')
.map((line) => line.includes('electron_mirror') ? line.replace('#', '').trimStart() : line)
.join('\n')

writeFileSync('.npmrc', npmrcContent)
}

function execSync(command: string) {
return cp.execSync(command, { cwd: generatePath, encoding: 'utf8' })
}

function writeFileSync(file: string, content: string) {
return fs.writeFileSync(path.join(generatePath, file), content)
}

function readFileSync(file: string) {
return fs.readFileSync(path.join(generatePath, file), 'utf8')
}

function intervalTask<R>(fn: (args: { stop: () => void }) => R | Promise<R>, options?: {
delay?: number
timeout?: number
}) {
const {
delay = 99,
timeout = 1000 * 60 * 1,
} = options ?? {}
const startTime = Date.now()
let done = false

return new Promise<R>((resolve, reject) => {
const run = async () => {
if (Date.now() - startTime > timeout) {
reject('Interval task timeout')
return
}

const result = await fn({
stop() {
done = true
},
})
if (done) {
resolve(result)
} else {
setTimeout(run, delay)
}
}
run()
})
}

function getDom(selector: string) {
return intervalTask(async (args) => {
const dom = await page.$(selector)
if (dom) {
args.stop()
return dom
}
})
}
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,9 @@
"devDependencies": {
"@types/node": "^22.1.0",
"@types/prompts": "^2.4.9",
"electron": "^33.0.2",
"execa": "^9.3.0",
"playwright": "^1.48.2",
"pnpm": "9.7.0",
"typescript": "^5.5.4",
"vite": "^5.4.0",
Expand Down
Loading