Skip to content

Commit

Permalink
feat: add e2e test (#51)
Browse files Browse the repository at this point in the history
* feat: add e2e test

* test: compatible windows platform

* test: e2e test pass ubuntu

* test: update e2e log

* test: set testTimeout 1000 * 29
  • Loading branch information
caoxiemeihao authored Oct 31, 2024
1 parent defcf39 commit 2553fe9
Show file tree
Hide file tree
Showing 5 changed files with 814 additions and 26 deletions.
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

0 comments on commit 2553fe9

Please sign in to comment.