diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 5648dea6..22e8a5e1 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -73,14 +73,10 @@ jobs: run: sudo apt update && sudo apt install --no-install-recommends libfftw3-dev quantum-espresso - name: Install Python dependencies - run: pip install -e .[pre-commit,tests] - - - name: Copy custom node file, add custom node path to sys path run: | - mkdir ~/.scinode - mkdir ~/.scinode/custom_node - export PYTHONPATH=~/.scinode/custom_node/:$PYTHONPATH - echo "PYTHONPATH=$PYTHONPATH" >> $GITHUB_ENV + pip install -e .[pre-commit,tests] + playwright install + - name: Create AiiDA profile run: verdi setup -n --config .github/config/profile.yaml diff --git a/.gitignore b/.gitignore index 1040b180..c7697311 100644 --- a/.gitignore +++ b/.gitignore @@ -131,3 +131,4 @@ dmypy.json # *.pdf tests/work +/tests/**/*.png diff --git a/aiida_worktree/web/frontend/public/index.html b/aiida_worktree/web/frontend/public/index.html index aa069f27..b2c0d7c8 100644 --- a/aiida_worktree/web/frontend/public/index.html +++ b/aiida_worktree/web/frontend/public/index.html @@ -24,7 +24,7 @@ work correctly both with client-side routing and a non-root public URL. Learn how to configure a non-root public URL by running `npm run build`. --> - React App + AiiDA-WorkTree App diff --git a/pyproject.toml b/pyproject.toml index 28294757..ed2924c3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -58,6 +58,7 @@ pre-commit = [ tests = [ "pytest~=7.0", "pytest-cov~=2.7,<2.11", + "playwright", ] [project.scripts] diff --git a/pytest.ini b/pytest.ini new file mode 100644 index 00000000..e69de29b diff --git a/tests/README.md b/tests/README.md new file mode 100644 index 00000000..9b1367fa --- /dev/null +++ b/tests/README.md @@ -0,0 +1,8 @@ + +## Requirements + +In order to run the test for the web frontend, one need to install + +```console +playwright install +``` diff --git a/tests/web/conftest.py b/tests/web/conftest.py new file mode 100644 index 00000000..09e765cf --- /dev/null +++ b/tests/web/conftest.py @@ -0,0 +1,27 @@ +import pytest +from fastapi.testclient import TestClient +from aiida_worktree.web.backend.app.api import app +from playwright.sync_api import sync_playwright + + +# Define a fixture for the FastAPI app client +@pytest.fixture(scope="module") +def client(): + return TestClient(app) + + +# Define a fixture for the browser +@pytest.fixture(scope="module") +def browser(): + with sync_playwright() as p: + browser = p.chromium.launch() + yield browser + browser.close() + + +# Define a fixture for the page +@pytest.fixture(scope="module") +def page(browser): + with browser.new_page() as page: + yield page + page.close() diff --git a/tests/web/test_backend.py b/tests/web/test_backend.py new file mode 100644 index 00000000..f563720d --- /dev/null +++ b/tests/web/test_backend.py @@ -0,0 +1,9 @@ +# Sample test case for the root route +def test_root_route(client): + response = client.get("/api") + assert response.status_code == 200 + assert response.json() == {"message": "Welcome to AiiDA-WorkTree."} + + +# Add more test cases for your other routes and features +# For example, testing authentication, database interactions, etc. diff --git a/tests/web/test_frontend.py b/tests/web/test_frontend.py new file mode 100644 index 00000000..506b1e90 --- /dev/null +++ b/tests/web/test_frontend.py @@ -0,0 +1,63 @@ +import pytest + + +def test_homepage(page): + page.goto("http://localhost:3000") + + assert page.title() == "AiiDA-WorkTree App" + + # Check for the existence of a specific element on the page + # Attempt to locate the element + element = page.locator("a[href='/worktree']") + + # Check if the element is found + if not element.is_visible(): + pytest.fail("Element 'a[href='/wortre']' not found on the page") + + +def test_worktree(page): + page.goto("http://localhost:3000/worktree") + + # Check for the existence of a specific element on the page + + # Verify the presence of the WorkTreeTable heading + assert page.locator("h2").inner_text() == "WorkTree" + + # Verify the presence of the search input + assert page.locator(".search-input").is_visible() + + # Verify the presence of the table header columns + # Verify the presence of the table header columns + assert page.locator("th:has-text('PK')").is_visible() + assert page.locator("th:has-text('Created')").is_visible() + assert page.locator("th:has-text('Process Label')").is_visible() + assert page.locator("th:has-text('State')").is_visible() + assert page.locator("th:has-text('Actions')").is_visible() + + # Verify the presence of pagination controls + assert page.locator(".pagination").is_visible() + + # Verify the presence of at least one row in the table + assert page.locator("tr").count() >= 2 # Including header row + + +def test_worktree_item(page, wt_calcfunction): + + wt = wt_calcfunction + wt.submit(wait=True) + page.goto("http://localhost:3000/worktree/{}".format(wt.pk)) + page.wait_for_timeout(3000) + + page.get_by_text("sumdiff3").is_visible() + + # Simulate user interaction (e.g., clicking a button) + # Replace the selector with the actual selector of the button you want to click + # You should identify the button that triggers an action in your component + page.get_by_role("button", name="Arrange").click() + page.wait_for_timeout(3000) + # Capture a screenshot + screenshot = page.screenshot() + + # Save the screenshot to a file + with open("screenshot.png", "wb") as f: + f.write(screenshot)