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

Add Puppeteer for End-to-End Tests #567

Merged
merged 24 commits into from
Feb 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
51fb052
Add basic puppeteer example
garrettmflynn Jan 17, 2024
81ea3c4
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jan 17, 2024
aa0b62d
Merge branch 'main' into puppeteer
CodyCBakerPhD Jan 17, 2024
ef1256c
Try waiting longer before querying with Puppeteer
garrettmflynn Jan 17, 2024
62a29d4
Update puppeteer.ts
garrettmflynn Jan 18, 2024
bafb8e8
Attempt without coverage
garrettmflynn Jan 29, 2024
7f89491
Merge branch 'main' into puppeteer
garrettmflynn Jan 29, 2024
e39d7e5
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jan 29, 2024
fcb9dbd
Update testing.yml
garrettmflynn Jan 30, 2024
12f419f
Merge branch 'main' into puppeteer
CodyCBakerPhD Jan 30, 2024
9d297bd
Update puppeteer.ts
garrettmflynn Jan 31, 2024
62fdcc0
Add logging and remove screenshot
garrettmflynn Jan 31, 2024
2bfa6a9
Fix error
garrettmflynn Jan 31, 2024
448173a
Add messages during test
garrettmflynn Jan 31, 2024
919dcb2
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jan 31, 2024
53aa726
Update e2e.test.ts
garrettmflynn Jan 31, 2024
637bff5
Merge branch 'puppeteer' of https://github.com/NeurodataWithoutBorder…
garrettmflynn Jan 31, 2024
32a6cfd
Run on ubuntu with xvfb, start tests immediately when ready, and exte…
garrettmflynn Jan 31, 2024
3ced224
Change spawn to exec
garrettmflynn Jan 31, 2024
b1cba48
Update puppeteer.ts
garrettmflynn Jan 31, 2024
8ea3668
Fix for Windows (long open time)
garrettmflynn Jan 31, 2024
b92827f
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jan 31, 2024
d03ae81
Cleanup
garrettmflynn Jan 31, 2024
eb41d02
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jan 31, 2024
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
8 changes: 7 additions & 1 deletion .github/workflows/testing.yml
Original file line number Diff line number Diff line change
Expand Up @@ -71,9 +71,15 @@ jobs:
- name: Install GUIDE
run: npm ci

- name: Run tests
- if: matrix.os != 'ubuntu-latest'
name: Run tests
run: npm run test:coverage

- if: matrix.os == 'ubuntu-latest'
name: Run tests with xvfb
run: xvfb-run --auto-servernum --server-args="-screen 0 1280x960x24" -- npm run test:coverage


- name: Upload coverage reports to Codecov
uses: codecov/codecov-action@v3
env:
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

dist
out
tests/screenshots

coverage

Expand Down
3,245 changes: 2,568 additions & 677 deletions package-lock.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@
"lit": "^2.6.1",
"lottie-web": "^5.9.5",
"notyf": "^3.9.0",
"puppeteer": "^21.7.0",
"sweetalert2": "^11.6.13",
"tippy.js": "^6.3.7",
"url": "^0.11.3",
Expand Down
39 changes: 29 additions & 10 deletions src/main/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,14 @@ import icon from '../renderer/assets/img/logo-guide-draft.png?asset'
import splashHTML from './splash-screen.html?asset'
import preloadUrl from './../preload/preload.js?asset'

const runByTestSuite = !!process.env.VITEST

// Enable remote debugging port for Vitest
if (runByTestSuite) {
app.commandLine.appendSwitch('remote-debugging-port', `${8315}`) // Mirrors the global electronDebugPort variable
app.commandLine.appendSwitch('remote-allow-origins', '*') // Allow all remote origins
}

// autoUpdater.channel = "latest";

/*************************************************************
Expand All @@ -37,6 +45,8 @@ const PYINSTALLER_NAME = "nwb-guide"
const isWindows = process.platform === 'win32'




let pyflaskProcess: any = null;

let PORT: number | string | null = 4242;
Expand Down Expand Up @@ -383,13 +393,21 @@ app.on('activate', () => {
})


const root = runByTestSuite ? path.join(paths.root, '.test') : paths.root

if (runByTestSuite) onWindowReady(() => console.log('WINDOW READY FOR TESTING'))


const homeDirectory = app.getPath("home");
const appDirectory = path.join(homeDirectory, paths.root)
const appDirectory = path.join(homeDirectory, root)
const guidedProgressFilePath = path.join(appDirectory, ...paths.subfolders.progress);
const guidedConversionFolderPath = path.join(appDirectory, ...paths.subfolders.conversions);
const guidedStubFolderPath = path.join(appDirectory, ...paths.subfolders.preview);

if (runByTestSuite && fs.existsSync(appDirectory)) fs.rmSync(appDirectory, { recursive: true }) // Clear the test directory if it exists

function getEntries(path, type = 'isDirectory') {
if (!fs.existsSync(path)) return []
return fs.readdirSync(path, { withFileTypes: true })
.filter(dirent => dirent[type]())
.map(dirent => dirent.name)
Expand All @@ -416,16 +434,17 @@ app.on("window-all-closed", () => {
app.on("before-quit", async (ev: Event) => {

ev.preventDefault()
if (!runByTestSuite) {
const { response } = await dialog
.showMessageBox(BrowserWindow.getFocusedWindow() as BrowserWindow, {
type: "question",
buttons: ["Yes", "No"],
title: "Confirm",
message: "Any running process will be stopped. Are you sure you want to quit?",
})

const { response } = await dialog
.showMessageBox(BrowserWindow.getFocusedWindow() as BrowserWindow, {
type: "question",
buttons: ["Yes", "No"],
title: "Confirm",
message: "Any running process will be stopped. Are you sure you want to quit?",
})

if (response !== 0) return // Skip quitting
if (response !== 0) return // Skip quitting
}

try {
globalShortcut.unregisterAll();
Expand Down
3 changes: 2 additions & 1 deletion src/renderer/src/dependencies/simple.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@ export const reloadPageToHome = () => {
}; // Clear all query params

// Filesystem Management
const root = process.env.VITEST ? joinPath(paths.root, ".test") : paths.root;
export const homeDirectory = app?.getPath("home") ?? "";
export const appDirectory = homeDirectory ? joinPath(homeDirectory, paths.root) : "";
export const appDirectory = homeDirectory ? joinPath(homeDirectory, root) : "";
export const guidedProgressFilePath = homeDirectory ? joinPath(appDirectory, ...paths.subfolders.progress) : "";

export const previewSaveFolderPath = homeDirectory
Expand Down
24 changes: 24 additions & 0 deletions tests/e2e.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { describe, expect, test } from 'vitest'
import { connect } from './puppeteer'

import { mkdirSync } from 'fs'
import { join, dirname } from 'path'
import { fileURLToPath } from 'node:url'

const __dirname = dirname(fileURLToPath(import.meta.url));
const screenshotPath = join( __dirname, 'screenshots')
mkdirSync(screenshotPath, { recursive: true })


describe('E2E Test', () => {

const references = connect()

test('Ensure number of test pipelines starts at zero', async () => {
const page = references.page
const nPipelines = await page.evaluate(() => document.getElementById('guided-div-resume-progress-cards').children.length)
await page.screenshot({ path: join(screenshotPath, 'test.png'), fullPage: true });
expect(nPipelines).toBe(0)
})

})
1 change: 1 addition & 0 deletions tests/globals.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const electronDebugPort = 8315
79 changes: 79 additions & 0 deletions tests/puppeteer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@

import { afterAll, beforeAll, expect, describe, vi, test } from 'vitest'

import * as puppeteer from 'puppeteer'

import { exec } from 'child_process'
import { electronDebugPort } from './globals'

export const sharePort = 1234

export const sleep = (ms) => new Promise(resolve => setTimeout(resolve, ms))


const beforeStart = (timeout) => new Promise(async (resolve, reject) => {

const handleOutput = (data) => {
if (data.includes('WINDOW READY FOR TESTING')) resolve(true)
console.log(`[electron] ${data}`)
}

const process = exec('npm start') // Run Start Script from package.json
process.stdout.on('data', handleOutput);
process.stderr.on('data', handleOutput);
process.on('close', (code) => console.log(`[electron] Exited with code ${code}`));
await sleep(timeout) // Wait for five seconds for Electron to open

reject('Failed to open Electron window successfully.')
})

type BrowserTestOutput = {
info?: any
page?: puppeteer.Page,
browser?: puppeteer.Browser,
}

const timeout = 60 * 1000 // Wait for 1 minute for Electron to open (mostly for Windows)

export const connect = () => {


const output: BrowserTestOutput = {}


beforeAll(async () => {

await beforeStart(timeout)



// Ensure Electron will exit gracefully
const mockExit = vi.spyOn(process, 'exit').mockImplementation(() => {
mockExit.mockRestore()
});

const browserURL = `http://localhost:${electronDebugPort}`
const browser = output.browser = await puppeteer.launch({ headless: 'new' })
const page = output.page = await browser.newPage();
await page.goto(browserURL);
const endpoint = await page.evaluate(() => fetch(`json/version`).then(res => res.json()).then(res => res.webSocketDebuggerUrl))
await browser.close()
delete output.browser
delete output.page

// Connect to browser WS Endpoint
const browserWSEndpoint = endpoint.replace('localhost', '0.0.0.0')
output.browser = await puppeteer.connect({ browserWSEndpoint, defaultViewport: null })

const pages = await output.browser.pages()
output.page = pages[0]

}, timeout + 1000)

afterAll(async () => {
if (output.browser) await output.browser.close() // Will also exit the Electron instance
});

return output

}
Loading