Skip to content
Open
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
247 changes: 247 additions & 0 deletions .github/workflows/ai-test-generator.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,247 @@
# AI Test Generator
#
# Automatically generates a pytest test file from a plain English description.
# Non-technical team members can trigger this workflow from the GitHub Actions UI,
# describe the test in plain English, and get a ready-to-run test file committed
# back to the repository.
#
# Required secret: OPENAI_API_KEY

name: AI Test Generator

on:
push:
paths:
- '**/ai_testcases/*.txt'

workflow_dispatch:
inputs:
suite:
description: 'Target test suite'
required: true
type: choice
options:
- CaseSearch
- DataDictionary
- FindDataById
- Lookuptable
- MultiSelect
- PowerBI
- SplitScreenCaseSearch
- ElasticSearch
- ExportTests
- Formplayer
- HQSmokeTests
- P1P2Tests
- RequestAPI
- USH_CO_BHA
- MobileTest
- BHAStressTest

description:
description: 'Describe the test in plain English (what should the test do?)'
required: true
type: string

output_path:
description: 'Output file path (leave blank to auto-generate)'
required: false
type: string
default: ''

run_after_generate:
description: 'Run the generated test immediately after generating it?'
required: false
type: boolean
default: false

environment:
description: 'Environment to run the generated test against (only used if run_after_generate is true)'
required: false
type: choice
default: 'staging'
options:
- staging
- production
- eu
- india

commit_result:
description: 'Commit the generated test file back to the repository?'
required: false
type: boolean
default: true

jobs:
generate:
name: Generate Test for '${{ inputs.suite }}'
runs-on: ubuntu-latest

outputs:
generated_file: ${{ steps.generate.outputs.generated_file }}

steps:
- uses: actions/checkout@v2

- name: Set up Python 3.13
uses: actions/setup-python@v2
with:
python-version: '3.13'

- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install openai>=1.0.0

- name: Generate from txt files (on push)
if: github.event_name == 'push'
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
run: |
# Find only the txt files that were added/changed in this push
CHANGED_TXT=$(git diff --name-only HEAD~1 HEAD 2>/dev/null || git diff --name-only HEAD | grep "ai_testcases/.*\.txt" || true)
if [ -z "$CHANGED_TXT" ]; then
echo "No new/changed txt files in this push — processing all pending files"
python ai_test_generator/process_testcases.py
else
echo "Processing changed files:"
echo "$CHANGED_TXT"
for f in $CHANGED_TXT; do
python ai_test_generator/process_testcases.py --file "$f" --force
done
fi

- name: Generate from description (manual trigger)
if: github.event_name == 'workflow_dispatch'
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
run: |
python ai_test_generator/generate_test.py \
--suite "${{ inputs.suite }}" \
--description "${{ inputs.description }}" \
${{ inputs.output_path != '' && format('--output "{0}"', inputs.output_path) || '' }}

- name: Commit all generated test files
run: |
git config user.name "github-actions[bot]"
git config user.email "github-actions[bot]@users.noreply.github.com"
# Stage all newly generated test files
git add '**/test_ai_*.py' '**/test_*_ai_generated.py' 2>/dev/null || true
if git diff --cached --quiet; then
echo "No new files to commit"
else
GENERATED_FILES=$(git diff --cached --name-only)
echo "Committing generated files:"
echo "$GENERATED_FILES"
git commit -m "feat(ai-gen): generate tests from ai_testcases txt files

Generated by: AI Test Generator (run #${{ github.run_number }})
Triggered by: ${{ github.actor }}"
git push
fi

- name: Upload all generated tests as artifact
uses: actions/upload-artifact@v4
with:
name: generated-tests-${{ github.run_id }}
path: |
**/test_ai_*.py
**/test_*_ai_generated.py
retention-days: 30

- name: Summary
run: |
echo "## AI Test Generator Summary" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "| Field | Value |" >> $GITHUB_STEP_SUMMARY
echo "|-------|-------|" >> $GITHUB_STEP_SUMMARY
echo "| Trigger | ${{ github.event_name }} |" >> $GITHUB_STEP_SUMMARY
echo "| Run | #${{ github.run_number }} |" >> $GITHUB_STEP_SUMMARY
echo "| Triggered by | ${{ github.actor }} |" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### Generated Files" >> $GITHUB_STEP_SUMMARY
find . -name "test_ai_*.py" -newer ai_test_generator/process_testcases.py \
! -path "./venv/*" ! -path "./.git/*" | while read f; do
echo "- \`$f\`" >> $GITHUB_STEP_SUMMARY
done

run_generated_test:
name: Run Generated Test on '${{ inputs.environment }}'
needs: generate
if: ${{ inputs.run_after_generate == true }}
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2
with:
# Pull latest so we get the newly committed test file
ref: ${{ github.ref }}

- name: Set up Python 3.13
uses: actions/setup-python@v2
with:
python-version: '3.13'

- name: Pull latest commit (get generated test)
if: ${{ inputs.commit_result == true }}
run: git pull

- name: Download generated test artifact (if not committed)
if: ${{ inputs.commit_result == false }}
uses: actions/download-artifact@v4
with:
name: generated-test-${{ inputs.suite }}-${{ github.run_id }}
path: ${{ needs.generate.outputs.generated_file && '' || '.' }}

- name: Install suite dependencies
run: |
python -m pip install --upgrade pip
# Install the suite's requires.txt if it exists
SUITE_DIR=$(python -c "
suites = {
'CaseSearch': 'Features/CaseSearch',
'DataDictionary': 'Features/DataDictionary',
'FindDataById': 'Features/FindDataById',
'Lookuptable': 'Features/Lookuptable',
'MultiSelect': 'Features/MultiSelect',
'PowerBI': 'Features/Powerbi_integration_exports',
'SplitScreenCaseSearch': 'Features/SplitScreenCaseSearch',
'ElasticSearch': 'ElasticSearchTests',
'ExportTests': 'ExportTests',
'Formplayer': 'Formplayer',
'HQSmokeTests': 'HQSmokeTests',
'P1P2Tests': 'P1P2Tests',
'RequestAPI': 'RequestAPI',
'USH_CO_BHA': 'USH_Apps/CO_BHA',
'MobileTest': 'MobileTest',
'BHAStressTest': 'QA_Requests/BHAStressTest',
}
print(suites.get('${{ inputs.suite }}', ''))
")
if [ -f "${SUITE_DIR}/requires.txt" ]; then
echo "Installing from ${SUITE_DIR}/requires.txt"
pip install -r "${SUITE_DIR}/requires.txt"
else
echo "No requires.txt found, installing common deps"
pip install pytest selenium pytest-html pytest-rerunfailures
fi

- name: Run generated test
env:
DIMAGIQA_ENV: ${{ inputs.environment }}
DIMAGIQA_LOGIN_USERNAME: ${{ secrets.DIMAGIQA_LOGIN_USERNAME }}
DIMAGIQA_LOGIN_PASSWORD: ${{ secrets.DIMAGIQA_LOGIN_PASSWORD }}
ENABLE_WAITS: 'true'
run: |
pytest -v "${{ needs.generate.outputs.generated_file }}" \
--html=report_generated_test.html \
--self-contained-html \
--tb=short

- name: Upload test results
if: ${{ success() || failure() }}
uses: actions/upload-artifact@v4
with:
name: generated-test-results-${{ inputs.environment }}-${{ github.run_id }}
path: report_generated_test.html
retention-days: 2
23 changes: 23 additions & 0 deletions ElasticSearchTests/ai_testcases/example_testcase.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
Suite: <Suite name - e.g. CaseSearch, HQSmokeTests, ExportTests, P1P2Tests>

Test 1: <Short name for first test>
Tags: <comma separated tags e.g. smoke, report, users>
1. <First step>
2. <Second step>
3. <Third step>
4. <Add as many steps as needed>
Expected Result: <What should happen>

Test 2: <Short name for second test>
Tags: <comma separated tags>
1. <First step>
2. <Second step>
3. <Third step>
Expected Result: <What should happen>

Test 3: <Short name for third test>
Tags: <comma separated tags>
1. <First step>
2. <Second step>
3. <Third step>
Expected Result: <What should happen>
23 changes: 23 additions & 0 deletions ExportTests/ai_testcases/example_testcase.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
Suite: <Suite name - e.g. CaseSearch, HQSmokeTests, ExportTests, P1P2Tests>

Test 1: <Short name for first test>
Tags: <comma separated tags e.g. smoke, report, users>
1. <First step>
2. <Second step>
3. <Third step>
4. <Add as many steps as needed>
Expected Result: <What should happen>

Test 2: <Short name for second test>
Tags: <comma separated tags>
1. <First step>
2. <Second step>
3. <Third step>
Expected Result: <What should happen>

Test 3: <Short name for third test>
Tags: <comma separated tags>
1. <First step>
2. <Second step>
3. <Third step>
Expected Result: <What should happen>
23 changes: 23 additions & 0 deletions Features/CaseSearch/ai_testcases/example_testcase.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
Suite: <Suite name - e.g. CaseSearch, HQSmokeTests, ExportTests, P1P2Tests>

Test 1: <Short name for first test>
Tags: <comma separated tags e.g. smoke, report, users>
1. <First step>
2. <Second step>
3. <Third step>
4. <Add as many steps as needed>
Expected Result: <What should happen>

Test 2: <Short name for second test>
Tags: <comma separated tags>
1. <First step>
2. <Second step>
3. <Third step>
Expected Result: <What should happen>

Test 3: <Short name for third test>
Tags: <comma separated tags>
1. <First step>
2. <Second step>
3. <Third step>
Expected Result: <What should happen>
31 changes: 31 additions & 0 deletions Features/CaseSearch/ai_testcases/search_and_submit_play_song.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
Suite: CaseSearch

Test 1: Search by song name and submit Play Song form
1. Login as user-1
2. Open the Music App
3. Open the Songs (Normal) menu
4. Clear selections on the case search page
5. Search for a case by song name using text input
6. Click the search button
7. Select the case and continue to forms
8. Open the Play Song form
9. Submit the form
Expected Result: Form submits successfully and user is returned to the app home screen

Test 2: Search with no results shows empty list
1. Login as user-1
2. Open the Music App
3. Open the Songs (Normal) menu
4. Search for a non-existent song name
5. Click the search button
Expected Result: Case list is empty with appropriate message

Test 3: Search using combobox filter
1. Login as user-2
2. Open the Music App
3. Open the Songs (Normal) menu
4. Clear selections on the case search page
5. Filter cases using a combobox property
6. Click the search button
7. Verify only matching cases appear in the list
Expected Result: Filtered case list shows only relevant results
23 changes: 23 additions & 0 deletions Features/DataDictionary/ai_testcases/example_testcase.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
Suite: <Suite name - e.g. CaseSearch, HQSmokeTests, ExportTests, P1P2Tests>

Test 1: <Short name for first test>
Tags: <comma separated tags e.g. smoke, report, users>
1. <First step>
2. <Second step>
3. <Third step>
4. <Add as many steps as needed>
Expected Result: <What should happen>

Test 2: <Short name for second test>
Tags: <comma separated tags>
1. <First step>
2. <Second step>
3. <Third step>
Expected Result: <What should happen>

Test 3: <Short name for third test>
Tags: <comma separated tags>
1. <First step>
2. <Second step>
3. <Third step>
Expected Result: <What should happen>
Loading
Loading