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

ci: add tests and github actions workflow #12

Merged
merged 1 commit into from
Oct 25, 2024
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
75 changes: 75 additions & 0 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
name: Test Workflow

on:
push:
branches:
- master
pull_request:

jobs:
unit-tests:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
python: ["3.10"]

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python }}

- name: Install uv
uses: astral-sh/setup-uv@v3

- name: Install dependencies
run: |
uv pip install ".[test]" --system

- name: Run unit tests
run: |
pytest tests/unit

integration-tests:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
python: ["3.10"]

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python }}

- name: Install uv
uses: astral-sh/setup-uv@v3

- name: Install dependencies
run: |
uv pip install ".[test]" --system

- name: Install Playwright
run: |
playwright install

- name: Run integration tests
run: |
pytest tests/integration --video=retain-on-failure --output=test-results

- name: upload test artifacts
uses: actions/upload-artifact@v4
with:
name: test-results-unit-os${{ matrix.os }}-python${{ matrix.python }}
path: test-results
include-hidden-files: true
4 changes: 3 additions & 1 deletion glue_solara/hooks.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,12 @@ def connect():
solara.use_effect(connect, [id(hub)])


def use_glue_watch_close(app: glue_jupyter.JupyterApplication):
def use_glue_watch_close(app: glue_jupyter.JupyterApplication, on_msg=None):
counter, set_counter = solara.use_state(0)

def remove_viewer(msg):
if on_msg is not None:
on_msg(msg)
viewers = app._viewer_refs
for _viewer in viewers:
viewer = _viewer()
Expand Down
4 changes: 4 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ dev = [
"mypy",
]

test = [
"pytest-ipywidgets",
]

[tool.ruff]
ignore-init-module-imports = true
fix = true
Expand Down
Empty file added tests/integration/__init__.py
Empty file.
94 changes: 94 additions & 0 deletions tests/integration/basics_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import playwright.sync_api
from playwright.sync_api import expect


def test_add_data_current_viewer(
page_session: playwright.sync_api.Page, solara_server, solara_app, assert_solara_snapshot
):
with solara_app("glue_solara.app"):
page_session.goto(solara_server.base_url)
add_data = page_session.locator("button", has_text="load data")
add_data.wait_for()
add_data.click()
expect(page_session.locator("button")).to_have_count(4)
page_session.locator("button", has_text="add w5 data").click()
page_session.locator("button", has_text="a 2d image").click()
page_session.locator("div.bqplot.figure").wait_for()
add_to_figure = page_session.locator(
"button.v-btn--icon:not(.v-btn--disabled)", has=page_session.locator("i.mdi-tab-plus")
)
expect(add_to_figure).to_have_count(1)
add_to_figure.click()
# Tried to assert with screenshot, but seems the graph is not consistent
# assert_solara_snapshot(page_session.locator("div.bqplot.figure").screenshot())
expect(page_session.get_by_role("button", disabled=True)).to_have_count(2)


def test_tabbed_viewers(page_session: playwright.sync_api.Page, solara_server, solara_app):
with solara_app("glue_solara.app"):
page_session.goto(solara_server.base_url)
add_data = page_session.locator("button", has_text="load data")
add_data.wait_for()
add_data.click()
page_session.locator("button", has_text="add w5 data").click()
page_session.locator("button", has_text="a 2d image").click()
page_session.locator("div.bqplot.figure").wait_for()
add_figure = page_session.locator("button", has=page_session.locator("i.mdi-tab")).nth(1)
expect(add_figure).to_be_attached()
add_figure.click()
page_session.locator("button", has_text="add").click()
expect(page_session.locator("div.v-tab")).to_have_count(2)


def test_tabbed_viewer_close(page_session: playwright.sync_api.Page, solara_server, solara_app):
with solara_app("glue_solara.app"):
page_session.goto(solara_server.base_url)
add_data = page_session.get_by_role("button", name="load data")
add_data.wait_for()
add_data.click()
page_session.locator("button", has_text="add w5 data").click()
page_session.locator("button", has_text="a 2d image").click()
page_session.locator("div.bqplot.figure").wait_for()
close_viewer = page_session.locator("button", has=page_session.locator("i.mdi-close"))
expect(close_viewer).to_have_count(1)
close_viewer.click()
expect(page_session.locator("div.bqplot.figure")).not_to_be_attached()
expect(page_session.get_by_text("What do you want to visualize")).to_be_visible()


def test_mdi_viewers(page_session: playwright.sync_api.Page, solara_server, solara_app):
with solara_app("glue_solara.app"):
page_session.goto(solara_server.base_url)
add_data = page_session.locator("button", has_text="load data")
add_data.wait_for()
add_data.click()
page_session.locator("button", has_text="add w5 data").click()
page_session.get_by_role("button", name="mdi").click()
page_session.locator("button", has_text="a 2d image").click()
page_session.locator("div.glue-solara__window").wait_for()
expect(page_session.locator("div.glue-solara__window")).to_have_count(1)
add_figure = page_session.locator("button", has=page_session.locator("i.mdi-tab")).nth(1)
expect(add_figure).to_be_attached()
add_figure.click()
page_session.locator("button", has_text="add").click()
expect(page_session.locator("div.glue-solara__window")).to_have_count(2)


def test_mdi_viewers_close(page_session: playwright.sync_api.Page, solara_server, solara_app):
with solara_app("glue_solara.app"):
page_session.goto(solara_server.base_url)
add_data = page_session.get_by_role("button", name="load data")
add_data.wait_for()
add_data.click()
page_session.locator("button", has_text="add w5 data").click()
page_session.get_by_role("button", name="mdi").click()
page_session.locator("button", has_text="a 2d image").click()
page_session.locator("div.glue-solara__window").wait_for()
expect(page_session.locator("div.glue-solara__window")).to_have_count(1)
close_button = page_session.locator(
"button", has=page_session.locator("i.mdi-close-circle-outline")
)
expect(close_button).to_have_count(1)
close_button.click()
expect(page_session.locator("div.glue-solara__window")).not_to_be_attached()
expect(page_session.get_by_text("What do you want to visualize")).to_be_visible()
Empty file added tests/unit/__init__.py
Empty file.
9 changes: 9 additions & 0 deletions tests/unit/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from pathlib import Path

from glue_jupyter.data import require_data


def pytest_sessionstart(session):
# Ensure that required example data is available
if not Path("w5.fits").exists():
require_data("Astronomy/W5/w5.fits")
62 changes: 62 additions & 0 deletions tests/unit/hooks_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
from unittest.mock import MagicMock

import ipyvuetify as v
import solara
from glue.core.message import Message
from glue_jupyter.app import JupyterApplication

from glue_solara.hooks import ClosedMessage, use_glue_watch, use_glue_watch_close


def test_use_glue_watch():
glue_app = JupyterApplication()
handler = MagicMock()

class CustomMessage(Message):
def __init__(self):
super().__init__(MagicMock())

@solara.component
def TestComponent():
use_glue_watch(glue_app.session.hub, CustomMessage, on_msg=handler)

box, rc = solara.render(TestComponent(), handle_error=False)
assert len(glue_app.session.hub._subscriptions) == 5
assert handler.call_count == 0
glue_app.session.hub.broadcast(CustomMessage())
assert handler.call_count == 1
box.close()


def test_use_glue_watch_close():
glue_app = JupyterApplication()
handler = MagicMock()

@solara.component
def TestComponent():
use_glue_watch_close(glue_app, on_msg=handler)

def create_viewer():
# There has to be some data added before we can create a viewer
glue_app.load_data("w5.fits")
glue_app.scatter2d(show=False)

def close_viewer():
msg = ClosedMessage(glue_app.viewers[0])
glue_app.session.hub.broadcast(msg)

solara.Button("open", on_click=create_viewer)
solara.Button("close", on_click=close_viewer)

box, rc = solara.render(TestComponent(), handle_error=False)
assert len(glue_app.session.hub._subscriptions) == 5
assert len(glue_app._viewer_refs) == 0
assert handler.call_count == 0
open_button, close_button = rc.find(v.Btn)
open_button.widget.click()
assert len(glue_app._viewer_refs) == 1
assert handler.call_count == 0
close_button.widget.click()
assert len(glue_app._viewer_refs) == 0
assert handler.call_count == 1
box.close()