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

tests: frontend test framework setup with playwright #268

Merged
merged 36 commits into from
Mar 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
7178168
test: frontend test framework setup with playwright
raaymax Feb 27, 2024
bd2c6cb
chore: added to CI
raaymax Feb 27, 2024
61e2bc9
chore: disable frontend tests on CI
raaymax Feb 27, 2024
a248ec7
chore: fix linter errors in tests
raaymax Feb 28, 2024
b7065d1
tests: testing drag and drop of components
raaymax Feb 29, 2024
1b5beec
refactor: playwright tests are now e2e_tests
raaymax Feb 29, 2024
793c074
chore: added more tests
raaymax Mar 1, 2024
7795b1e
ci: added e2e tests to ci workflow
raaymax Mar 1, 2024
8e67c10
chore: working on adding e2e tests to ci
raaymax Mar 1, 2024
5e2b521
chore: trying separate gh action for playwright
raaymax Mar 1, 2024
18bb586
chore: CI test
raaymax Mar 1, 2024
8f292a8
chore: package lock update
raaymax Mar 1, 2024
699d01e
chore: fixed alferd ci
raaymax Mar 1, 2024
2afd896
chore: ci job check
raaymax Mar 1, 2024
82f4cdf
chore: fixed e2e action issue
raaymax Mar 1, 2024
7a92821
chore: removed unnecesarry steps
raaymax Mar 1, 2024
9cbf228
tests: fixing e2e tests on CI
raaymax Mar 3, 2024
833bdb7
tests: added artifacts
raaymax Mar 3, 2024
ac68175
Merge branch 'dev' into frontend-tests
raaymax Mar 4, 2024
9bddde8
chore: scripts to main package.json
raaymax Mar 4, 2024
4dbfb26
chore: added missing script to package.json
raaymax Mar 4, 2024
2dd527c
chore: date input fix
raaymax Mar 4, 2024
3244c09
chore: fixed ocational server startup error
raaymax Mar 4, 2024
379ea51
chore: fixed failing tests
raaymax Mar 4, 2024
f31fe0f
build: building all parts at once
raaymax Mar 5, 2024
eb08d1d
build: separated docs build from main build
raaymax Mar 5, 2024
b733cae
ci: add job for each browser
raaymax Mar 5, 2024
54cea33
ci: use of matrix strategy to run tests in parallel
raaymax Mar 5, 2024
c144c5a
ci: fix e2e running in all ci runs
raaymax Mar 5, 2024
45e26ea
fix: added masks to failing components
raaymax Mar 5, 2024
ee02678
ci: fixed firefox issues and installing only necessary packages
raaymax Mar 5, 2024
494087f
Merge branch 'dev' into frontend-tests
raaymax Mar 5, 2024
ea810c3
tests: added missing tests
raaymax Mar 5, 2024
09b21dc
tests: retriable tests
raaymax Mar 5, 2024
e052d17
chore: changes according to review
raaymax Mar 5, 2024
4c2d267
style: code cleanup
raaymax Mar 5, 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
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")) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any ideas to make this less hacky in the future? Something like a health check, some signal I don't know about?

Probably useful for other purposes too.

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
Loading