Skip to content

Commit

Permalink
Merge pull request #268 from raaymax/frontend-tests
Browse files Browse the repository at this point in the history
tests: frontend test framework setup with playwright
  • Loading branch information
ramedina86 authored Mar 5, 2024
2 parents 29e4bb3 + 4c2d267 commit 72a2f75
Show file tree
Hide file tree
Showing 38 changed files with 9,454 additions and 32 deletions.
43 changes: 43 additions & 0 deletions .github/workflows/ci-e2e.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
name: ci-e2e
on:
push:
branches: [ dev, master]
pull_request:
branches: [ dev, master]

jobs:
tests:
runs-on: ubuntu-latest
strategy:
matrix:
browser: [ "chromium", "firefox", "webkit" ]
steps:
- uses: actions/checkout@v3

- name: Set up Python 3.11.8
uses: actions/setup-python@v4
with:
python-version: "3.11.8"

- name: Use Node.js 18
uses: actions/setup-node@v4
with:
node-version: 18

- name: update package manager & install python3 environment
run: |
sudo pip install poetry
poetry install --with build
- name: Install npm dependencies
run: npm ci

- name: Build UI
run: npm run build

- name: Install E2E browsers
working-directory: e2e_tests
run: npx playwright install ${{ matrix.browser }} --with-deps

- name: Run E2E tests
run: poetry run alfred ci --e2e=${{ matrix.browser }}
7 changes: 2 additions & 5 deletions .github/workflows/ci-macos.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,7 @@ jobs:
poetry install --with build
- name: install npm environment
run: |
cd ui
npm install
run: npm ci

- name: run continuous integration pipeline
run: |
poetry run alfred ci
run: poetry run alfred ci
7 changes: 2 additions & 5 deletions .github/workflows/ci-windows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,7 @@ jobs:
poetry install --with build
- name: install npm environment
run: |
cd ui
npm install
run: npm ci

- name: run continuous integration pipeline
run: |
poetry run alfred ci
run: poetry run alfred ci
7 changes: 2 additions & 5 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,7 @@ jobs:
poetry install --with build
- name: install npm environment
run: |
cd ui
npm install
run: npm ci

- name: run continuous integration pipeline
run: |
poetry run alfred ci
run: poetry run alfred ci
2 changes: 1 addition & 1 deletion alfred/build.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,4 @@ def build_poetry():
if os.path.isdir(directory):
shutil.rmtree(directory)

alfred.run("poetry build")
alfred.run("poetry build")
9 changes: 6 additions & 3 deletions alfred/ci.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,16 @@
@alfred.command("ci", help="continuous integration pipeline")
@alfred.option('--front', '-f', help="run for frontend only", is_flag=True, default=False)
@alfred.option('--back', '-b', help="run for backend only", is_flag=True, default=False)
def ci(front, back):
if back or (not front and not back):
@alfred.option('--e2e', '-e', help="run for end-to-end only", default=None)
def ci(front, back, e2e):
if back or (not front and not back and not e2e):
alfred.invoke_command("ci.mypy")
alfred.invoke_command("ci.pytest")
if front or (not front and not back):
if front or (not front and not back and not e2e):
alfred.invoke_command("npm.lint")
alfred.invoke_command("npm.build")
if e2e:
alfred.invoke_command("npm.e2e", browser=e2e)

@alfred.command("ci.mypy", help="typing checking with mypy on ./src/streamsync")
def ci_mypy():
Expand Down
8 changes: 5 additions & 3 deletions alfred/npm.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,17 @@

@alfred.command("npm.lint", help="lint check ui code")
def npm_lint():
os.chdir("ui")
alfred.run("npm run lint:ci")

@alfred.command("npm.e2e", help="run e2e tests")
@alfred.option('--browser', '-b', help="run e2e tests on specified browser", default='chromium')
def npm_test(browser):
alfred.run("npm run e2e:"+browser+":ci")

@alfred.command("npm.build", help="build ui code")
def npm_build():
os.chdir("ui")
alfred.run("npm run build")

@alfred.command("npm.build_custom_components", help="build custom components")
def ui_build_custom():
os.chdir("ui")
alfred.run("npm run custom.build")
6 changes: 3 additions & 3 deletions docs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
"description": "",
"main": "index.js",
"scripts": {
"docs:dev": "vitepress dev docs",
"docs:build": "vitepress build docs",
"docs:preview": "vitepress preview docs"
"dev": "vitepress dev docs",
"build": "vitepress build docs",
"preview": "vitepress preview docs"
},
"dependencies": {
"vitepress": "^1.0.0-rc.44",
Expand Down
6 changes: 6 additions & 0 deletions e2e_tests/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
runtime/
node_modules/
/test-results/
/playwright-report/
/blob-report/
/playwright/.cache/
148 changes: 148 additions & 0 deletions e2e_tests/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
const express = require("express");
const fs = require("node:fs").promises;
const { spawn } = require("node:child_process");
const httpProxy = require("http-proxy");

class Streamsync {
constructor() {
this.process = null;
this.initialized = false;
this.port = 7358;
this.busy = false;
}

async start() {
return new Promise((resolve, reject) => {
if (this.process !== null) {
this.process.kill();
}
const ss = spawn(
"streamsync",
["edit", "./runtime", "--port", this.port]
);
this.process = ss;
const startupTimeout = setTimeout(() => {
// eslint-disable-next-line no-console
console.error("Streamsync startup timeout");
ss.kill();
reject();
}, 5000);

ss.stdout.on("data", (data) => {
// eslint-disable-next-line no-console
console.log(
`[${ss.pid}] stdout: ${Buffer.from(data, "utf-8").toString()}`,
);
if (data.includes("Builder is available at")) {
this.initialized = true;
clearTimeout(startupTimeout);
resolve(ss);
}
});

ss.stderr.on("data", (data) => {
// eslint-disable-next-line no-console
console.error(`[${ss.pid}] stderr: ${data}`);
});

ss.on("close", () => {
// eslint-disable-next-line no-console
console.log(`[${ss.pid}] child process closed`);
});
ss.on("error", (err) => {
// eslint-disable-next-line no-console
console.log(`[${ss.pid}] child process error`, err);
});
ss.on("exit", (code) => {
// eslint-disable-next-line no-console
this.process = null;
console.log(
`[${ss.pid}] child process exited with code ${code}`,
);
});
});
}

async stop() {
return new Promise((resolve) => {
if (this.process) {
this.process.once("exit", () => {
resolve();
});
this.process.kill("SIGTERM");
} else {
resolve();
}
});
}

async restart() {
this.busy = true;
try {
await this.stop();
this.port += 1;
await this.start();
} catch (e) {
throw e;
} finally {
this.busy = false;
}
}

async loadPreset(preset) {
this.busy = true;
try {
await this.stop();
this.port += 1;
await fs.copyFile(`./presets/${preset}/ui.json`, "./runtime/ui.json");
await fs.copyFile(`./presets/${preset}/main.py`, "./runtime/main.py");
await this.start();
} catch (e) {
throw e;
} finally {
this.busy = false;
}
}
}

const ss = new Streamsync();
(async () => {
await fs.mkdir("runtime", { recursive: true });
})();

var proxy = httpProxy.createProxyServer();

proxy.on('error', function (e) {
// eslint-disable-next-line no-console
console.error(e);
});

const app = express();

app.get("/preset/:preset", async (req, res) => {
if(ss.busy) {
res.status(429).send("Server is busy");
return;
}
console.log("Loading preset", req.params.preset);
const preset = req.params.preset;
await ss.loadPreset(preset);
res.send("UI updated");
});

app.use((req, res) => {
if(ss.initialized === false) {
res.send("Server not initialized yet");
return;
}
proxy.web(req, res, {target: 'http://127.0.0.1:'+ ss.port});
})

const server = app.listen(7357, () => {
// eslint-disable-next-line no-console
console.log("Server is running on port 7357");
});

server.on('upgrade', (req, socket, head) => {
proxy.ws(req, socket, head, {target: 'ws://127.0.0.1:'+ss.port, ws: true});
});
Loading

0 comments on commit 72a2f75

Please sign in to comment.