-
Notifications
You must be signed in to change notification settings - Fork 0
And/add basic smoke tests #12
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
Changes from 9 commits
8a8a328
0b71267
e3203ac
b28eae3
e6daeef
c779f7e
b34fe68
e32ec59
cad5443
057d484
a8fcad7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| name: Setup Python + Playwright | ||
| description: Common setup for all Playwright-based smoke tests | ||
| inputs: | ||
| python-version: | ||
| description: Version of Python to use | ||
| required: false | ||
| default: "3.11" | ||
| exclude_inputs: | ||
| description: Comma-separated list of inputs to exclude from masking | ||
| required: false | ||
| default: target_url,course_id | ||
|
|
||
| runs: | ||
| using: composite | ||
| steps: | ||
| - name: Set up Python | ||
| uses: actions/setup-python@v5 | ||
| with: | ||
| python-version: ${{ inputs.python-version }} | ||
|
|
||
| - name: Install dependencies | ||
| run: | | ||
| pip install pytest-playwright | ||
| playwright install | ||
| shell: bash | ||
|
|
||
| - name: Hide the inputs values to keep them private in the logs | ||
| uses: levibostian/action-hide-sensitive-inputs@v1 | ||
| with: | ||
| exclude_inputs: ${{ inputs.exclude_inputs }} | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,171 @@ | ||
| name: Smoke Tests | ||
|
|
||
| on: | ||
| workflow_call: | ||
| inputs: | ||
| run_test: | ||
| description: Select desired test | ||
| required: true | ||
| type: string | ||
| target_url: | ||
| description: Base URL for the application | ||
| required: true | ||
| type: string | ||
| user_email: | ||
| description: Test user email | ||
| required: true | ||
| type: string | ||
| user_password: | ||
| description: Test user password | ||
| required: true | ||
| type: string | ||
| course_id: | ||
| description: Course ID to test viewing the course page | ||
| required: true | ||
| type: string | ||
| target_plugins: | ||
| description: Desired plugins to validate | ||
| required: true | ||
| type: string | ||
| unit_id: | ||
| description: Unit ID to test complete-multiplechoice-unit | ||
| required: true | ||
| type: string | ||
|
|
||
|
|
||
| jobs: | ||
| check-heartbeat: | ||
| if: ${{ inputs.run_test == 'All' || inputs.run_test == 'check-heartbeat'}} | ||
| name: Check Heartbeat | ||
| runs-on: ubuntu-latest | ||
|
|
||
| steps: | ||
| - name: Checkout actions-hub repo | ||
| uses: actions/checkout@v4 | ||
| with: | ||
| repository: nelc/actions-hub | ||
| ref: and/add-basic-smoke-tests | ||
| path: actions-hub | ||
|
|
||
| - name: Setup Python and Playwright | ||
| uses: ./actions-hub/.github/actions/setup-playwright | ||
|
|
||
| - name: Run heartbeat test | ||
| run: | | ||
| python actions-hub/scripts/smoke-tests/test_heartbeat.py \ | ||
| --base-url "${{ inputs.target_url }}" | ||
|
|
||
| validate-plugins: | ||
| if: ${{ inputs.run_test == 'All' || inputs.run_test == 'validate-plugins'}} | ||
| name: Validate eox plugins | ||
| runs-on: ubuntu-latest | ||
|
|
||
| steps: | ||
| - name: Checkout actions-hub repo | ||
| uses: actions/checkout@v4 | ||
| with: | ||
| repository: nelc/actions-hub | ||
| ref: and/add-basic-smoke-tests | ||
| path: actions-hub | ||
|
|
||
| - name: Setup Python and Playwright | ||
| uses: ./actions-hub/.github/actions/setup-playwright | ||
|
|
||
| - name: Validate eox plugins | ||
| run: | | ||
| python actions-hub/scripts/smoke-tests/test_eox_plugins.py \ | ||
| --base-url "${{ inputs.target_url }}" \ | ||
| --plugins ${{ inputs.target_plugins }} | ||
|
|
||
| login-user: | ||
| if: ${{ inputs.run_test == 'All' || inputs.run_test == 'login-user'}} | ||
| name: Login User Test | ||
| runs-on: ubuntu-latest | ||
|
|
||
| steps: | ||
| - name: Checkout actions-hub repo | ||
| uses: actions/checkout@v4 | ||
| with: | ||
| repository: nelc/actions-hub | ||
| ref: and/add-basic-smoke-tests | ||
| path: actions-hub | ||
|
|
||
| - name: Setup Python and Playwright | ||
| uses: ./actions-hub/.github/actions/setup-playwright | ||
|
|
||
| - name: Run login-user test | ||
| run: | | ||
| python actions-hub/scripts/smoke-tests/test_login_user.py \ | ||
| --base-url "${{ inputs.target_url }}" \ | ||
| --email "${{ inputs.user_email }}" \ | ||
| --password "${{ inputs.user_password }}" | ||
|
|
||
| view-course: | ||
| if: ${{ inputs.run_test == 'All' || inputs.run_test == 'view-course'}} | ||
| name: View Course Page Test | ||
| runs-on: ubuntu-latest | ||
|
|
||
| steps: | ||
| - name: Checkout actions-hub repo | ||
| uses: actions/checkout@v4 | ||
| with: | ||
| repository: nelc/actions-hub | ||
| ref: and/add-basic-smoke-tests | ||
| path: actions-hub | ||
|
|
||
| - name: Setup Python and Playwright | ||
| uses: ./actions-hub/.github/actions/setup-playwright | ||
|
|
||
| - name: Run view-course test | ||
| run: | | ||
| python actions-hub/scripts/smoke-tests/test_view_course.py \ | ||
| --base-url "${{ inputs.target_url }}" \ | ||
| --email "${{ inputs.user_email }}" \ | ||
| --password "${{ inputs.user_password }}" \ | ||
| --course-id "${{ inputs.course_id }}" | ||
|
|
||
| complete-multiplechoice-unit: | ||
| if: ${{ inputs.run_test == 'All' || inputs.run_test == 'complete-multiplechoice-unit'}} | ||
| name: Complete multiplechoice unit test | ||
| runs-on: ubuntu-latest | ||
|
|
||
| steps: | ||
| - name: Checkout actions-hub repo | ||
| uses: actions/checkout@v4 | ||
| with: | ||
| repository: nelc/actions-hub | ||
| ref: and/add-basic-smoke-tests | ||
| path: actions-hub | ||
|
|
||
| - name: Setup Python and Playwright | ||
| uses: ./actions-hub/.github/actions/setup-playwright | ||
|
|
||
| - name: Run complete-multiplechoice-unit test | ||
| run: | | ||
| python actions-hub/scripts/smoke-tests/test_complete_multiplechoice_unit.py \ | ||
| --base-url "${{ inputs.target_url }}" \ | ||
| --email "${{ inputs.user_email }}" \ | ||
| --password "${{ inputs.user_password }}" \ | ||
| --course-id "${{ inputs.course_id }}" \ | ||
| --unit-id "${{ inputs.unit_id }}" | ||
|
|
||
| register-user: | ||
| if: ${{ inputs.run_test == 'All' || inputs.run_test == 'register-user'}} | ||
| name: Register user test | ||
| runs-on: ubuntu-latest | ||
|
|
||
| steps: | ||
| - name: Checkout actions-hub repo | ||
| uses: actions/checkout@v4 | ||
| with: | ||
| repository: nelc/actions-hub | ||
| ref: and/add-basic-smoke-tests | ||
| path: actions-hub | ||
|
|
||
| - name: Setup Python and Playwright | ||
| uses: ./actions-hub/.github/actions/setup-playwright | ||
|
|
||
| - name: Run register-user test | ||
| run: | | ||
| python actions-hub/scripts/smoke-tests/test_register_user.py \ | ||
| --base-url "${{ inputs.target_url }}" |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,75 @@ | ||
| import argparse | ||
|
|
||
| from playwright.sync_api import TimeoutError, sync_playwright | ||
| from utils import login_user | ||
|
|
||
|
|
||
| def test_complete_multiplechoice_unit(base_url: str, course_id: str, unit_id: str, email: str, password: str): | ||
| """ | ||
| Smoke test to verify that a multiple choice unit can be completed. | ||
|
|
||
| Args: | ||
| base_url (str): The base URL of the platform. | ||
| course_id (str): The course ID to navigate into. | ||
| unit_id (str): The specific unit ID (usage key). | ||
| email (str): Login email. | ||
| password (str): Login password. | ||
| """ | ||
| unit_url = f"{base_url}/courses/{course_id}/jump_to_id/{unit_id}" | ||
|
|
||
| with sync_playwright() as p: | ||
| browser = p.chromium.launch() | ||
| page = browser.new_page() | ||
| login_user(page, base_url, email, password) | ||
| page.goto(unit_url) | ||
| page.wait_for_load_state("networkidle") | ||
|
|
||
| # Try to find the iframe that contains the unit content | ||
| iframe = page.frame_locator("#unit-iframe") | ||
| assert iframe is not None, "No iframe found containing unit content" | ||
|
|
||
| # Get the first problem | ||
| problems = iframe.locator("div.problem") | ||
| assert problems.count() > 0, "No problems found" | ||
| problem = problems.first | ||
|
|
||
| # Get problem choices | ||
| radios = problem.locator("input[type='radio']") | ||
| assert radios.count() > 0, "No multiple choice options found" | ||
|
|
||
| # Get Submit button | ||
| submit_button = problem.locator("button.submit") | ||
| assert submit_button.is_visible(), "Submit button not found" | ||
|
|
||
| for radio in radios.all(): | ||
| radio.click() | ||
| submit_button.click() | ||
| notification = problem.locator(".notification.success.notification-submit") | ||
|
|
||
| try: | ||
| notification.wait_for(state="visible", timeout=5000) | ||
| break | ||
| except TimeoutError: | ||
| continue | ||
|
|
||
| assert notification.is_visible(), "Success notification isn't visible" | ||
|
|
||
| browser.close() | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| parser = argparse.ArgumentParser(description="Smoke test: Complete a multiple choice unit") | ||
| parser.add_argument("--base-url", required=True, help="Base URL of the LMS") | ||
| parser.add_argument("--course-id", required=True, help="Course ID") | ||
| parser.add_argument("--unit-id", required=True, help="Unit ID (usage key)") | ||
| parser.add_argument("--email", required=True, help="User email for login") | ||
| parser.add_argument("--password", required=True, help="User password for login") | ||
| args = parser.parse_args() | ||
|
|
||
| test_complete_multiplechoice_unit( | ||
| base_url=args.base_url, | ||
| course_id=args.course_id, | ||
| unit_id=args.unit_id, | ||
| email=args.email, | ||
| password=args.password, | ||
| ) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,44 @@ | ||
| import argparse | ||
|
|
||
| from playwright.sync_api import sync_playwright | ||
|
|
||
|
|
||
| def test_plugin_versions(base_url: str, plugins: list[str]) -> None: | ||
| """ | ||
| Smoke test to verify that plugin info endpoints return a valid JSON with version info. | ||
|
|
||
| Args: | ||
| base_url (str): The base URL of the LMS. | ||
| plugins (list[str]): List of plugins to check. | ||
| """ | ||
| with sync_playwright() as p: | ||
| browser = p.chromium.launch() | ||
| page = browser.new_page() | ||
|
|
||
| for plugin in plugins: | ||
| full_url = f"{base_url.rstrip('/')}/{plugin}/eox-info" | ||
| print(f"→ Checking {full_url}...") | ||
|
|
||
| response = page.goto(full_url) | ||
| assert response is not None and response.ok, f"❌ Failed to load {full_url}" | ||
|
|
||
| try: | ||
| json_data = response.json() | ||
| except Exception as e: | ||
| raise AssertionError(f"❌ Invalid JSON response from {full_url}: {e}") | ||
|
|
||
| version = json_data.get("version") | ||
| assert version, f"❌ 'version' key not found in JSON from {full_url}" | ||
|
|
||
| print(f"✅ {plugin} version: {version}") | ||
|
|
||
| browser.close() | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| parser = argparse.ArgumentParser(description="Smoke test: Validate eox plugins") | ||
| parser.add_argument("--base-url", required=True, help="Base LMS URL") | ||
| parser.add_argument("--plugins", nargs="+", required=True, help="List of plugin to check") | ||
| args = parser.parse_args() | ||
|
|
||
| test_plugin_versions(base_url=args.base_url, plugins=args.plugins) |
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,34 @@ | ||||||
| import argparse | ||||||
|
|
||||||
| from playwright.sync_api import sync_playwright | ||||||
|
|
||||||
|
|
||||||
| def test_heartbeat(base_url: str): | ||||||
| """ | ||||||
| Smoke test to verify that the /heartbeat endpoint is reachable and returns HTTP 200. | ||||||
|
|
||||||
| Args: | ||||||
| base_url (str): The base URL of the platform. | ||||||
| """ | ||||||
| with sync_playwright() as p: | ||||||
| browser = p.chromium.launch() | ||||||
| page = browser.new_page() | ||||||
|
|
||||||
| response = page.goto(f"{base_url.rstrip('/')}/heartbeat") | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
you could do this. And also the ingration test could check by different key of dict, other services like celery and forum. So we could have the info if those services are working as expected.
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. is the test wrong? the test just checks a 200 code status it doesn't matter the response itself so if the service is down the status code would be 200 no matter what but the status key would be false ? |
||||||
|
|
||||||
| if not response or response.status != 200: | ||||||
| raise AssertionError( | ||||||
| f"❌ Heartbeat check failed. Status: {response.status if response else 'No response'}" | ||||||
| ) | ||||||
|
|
||||||
| print(f"✅ Heartbeat responded with HTTP {response.status}") | ||||||
|
|
||||||
| browser.close() | ||||||
|
|
||||||
|
|
||||||
| if __name__ == "__main__": | ||||||
| parser = argparse.ArgumentParser(description="Smoke test: Heartbeat Endpoint") | ||||||
| parser.add_argument("--base-url", required=True, help="Base URL of the platform") | ||||||
| args = parser.parse_args() | ||||||
|
|
||||||
| test_heartbeat(base_url=args.base_url) | ||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,37 @@ | ||
| import argparse | ||
|
|
||
| from playwright.sync_api import expect, sync_playwright | ||
| from utils import login_user | ||
|
|
||
|
|
||
| def test_login_user(base_url: str, email: str, password: str) -> None: | ||
| """ | ||
| Runs a login smoke test using Playwright against the specified base URL. | ||
|
|
||
| Args: | ||
| base_url (str): Base URL of the target application. | ||
| email (str): Email of the test user. | ||
| password (str): Password of the test user. | ||
|
|
||
| Raises: | ||
| AssertionError: If the login fails or the dashboard page is not reached. | ||
| """ | ||
| with sync_playwright() as p: | ||
| browser = p.chromium.launch() | ||
| page = browser.new_page() | ||
|
|
||
| login_user(page, base_url, email, password) | ||
|
|
||
| expect(page).to_have_url(f"{base_url}/dashboard") | ||
|
|
||
| browser.close() | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| parser = argparse.ArgumentParser(description="Run login smoke test using Playwright.") | ||
| parser.add_argument("--base-url", required=True, help="Base URL of the target application.") | ||
| parser.add_argument("--email", required=True, help="Login email.") | ||
| parser.add_argument("--password", required=True, help="Login password.") | ||
| args = parser.parse_args() | ||
|
|
||
| test_login_user(base_url=args.base_url, email=args.email, password=args.password) |

There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we add here a cache step like this.
https://github.com/nelc/eox-nelp/blob/76fdc2245533faa2a5f6f34fdd5476854dc706f4/.github/workflows/tests.yml#L22-L32
Also we could add a integration requirements file to add eg
pytest-playwright. And try to dont reconfigure python and the pip requirement for each test.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done