Skip to content

Commit 290b582

Browse files
authored
Add smoke tests & screenshots (#11)
* Add smoke tests & screenshots
1 parent ea9618e commit 290b582

File tree

20 files changed

+1110
-60
lines changed

20 files changed

+1110
-60
lines changed

.github/workflows/build-all-platforms.yml

Lines changed: 131 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,23 @@ jobs:
8282
force-avd-creation: false
8383
emulator-options: -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim -camera-back none
8484
disable-animations: true
85-
script: cd android && ./gradlew build connectedCheck
85+
working-directory: ./android
86+
script: |
87+
./gradlew build
88+
./gradlew :app:installDebug :app:installDebugAndroidTest
89+
adb shell am instrument -w -r -e debug false com.dermochelys.acidwarp.test/androidx.test.runner.AndroidJUnitRunner
90+
mkdir -p screenshots
91+
adb pull /storage/emulated/0/Android/data/com.dermochelys.acidwarp/files/screenshots screenshots/ || echo "No screenshots found"
92+
adb uninstall com.dermochelys.acidwarp || true
93+
adb uninstall com.dermochelys.acidwarp.test || true
94+
95+
- name: Upload screenshots
96+
if: always()
97+
uses: actions/upload-artifact@v4
98+
with:
99+
name: android-ui-test-screenshots
100+
path: android/screenshots/screenshots/*.png
101+
if-no-files-found: error
86102

87103
- name: Check Android ELF Alignment
88104
uses: Dermochelys/check-android-elf-alignment@v2
@@ -171,6 +187,24 @@ jobs:
171187
working-directory: linux
172188
run: cmake --build build --config Release
173189

190+
- name: Install test dependencies
191+
run: |
192+
sudo apt-get install -y xvfb scrot xdotool
193+
194+
- name: Run UI tests
195+
working-directory: linux
196+
run: |
197+
chmod +x ui_test.sh
198+
./ui_test.sh
199+
200+
- name: Upload screenshots
201+
if: always()
202+
uses: actions/upload-artifact@v4
203+
with:
204+
name: linux-ui-test-screenshots
205+
path: linux/screenshots/*.png
206+
if-no-files-found: error
207+
174208

175209

176210
# ============================================================================
@@ -187,8 +221,6 @@ jobs:
187221
steps:
188222
- name: Checkout repository
189223
uses: actions/checkout@v4
190-
with:
191-
symlinks: true
192224

193225
- name: Setup MSYS2
194226
uses: msys2/setup-msys2@v2
@@ -211,6 +243,16 @@ jobs:
211243
working-directory: windows
212244
run: cmake --build build --config Release
213245

246+
- name: Upload Windows build artifacts
247+
uses: actions/upload-artifact@v4
248+
with:
249+
name: windows-build
250+
path: |
251+
windows/build/*.exe
252+
windows/*.dll
253+
windows/ui_test.ps1
254+
if-no-files-found: error
255+
214256

215257

216258
# ============================================================================
@@ -227,22 +269,34 @@ jobs:
227269
- name: Select Xcode version
228270
run: sudo xcode-select -s /Applications/Xcode.app/Contents/Developer
229271

230-
- name: Build macOS app
272+
- name: Run UI tests
231273
working-directory: macos
274+
timeout-minutes: 20
232275
run: |
233-
xcodebuild -project acidwarp-macos.xcodeproj \
234-
-scheme acidwarp-macos \
235-
-configuration Release \
236-
-derivedDataPath ./build \
237-
CODE_SIGN_IDENTITY="" \
238-
CODE_SIGNING_REQUIRED=NO \
239-
CODE_SIGNING_ALLOWED=NO
240-
241-
- name: Create macOS app archive
242-
working-directory: macos
276+
chmod +x run-uitests.sh
277+
./run-uitests.sh
278+
279+
- name: Upload xcodebuild log
280+
if: failure()
281+
uses: actions/upload-artifact@v4
282+
with:
283+
name: macos-xcodebuild-log
284+
path: macos/xcodebuild.log
285+
if-no-files-found: ignore
286+
287+
- name: Extract screenshots from test results
288+
if: always()
243289
run: |
244-
cd build/Build/Products/Release
245-
zip -r ../../../../acidwarp-macos.zip "Acid Warp.app"
290+
chmod +x extract-test-screenshots.sh
291+
./extract-test-screenshots.sh macos macos/build macos/screenshots
292+
293+
- name: Upload screenshots
294+
if: always()
295+
uses: actions/upload-artifact@v4
296+
with:
297+
name: macos-ui-test-screenshots
298+
path: macos/screenshots/*.png
299+
if-no-files-found: error
246300

247301

248302

@@ -260,23 +314,61 @@ jobs:
260314
- name: Select Xcode version
261315
run: sudo xcode-select -s /Applications/Xcode.app/Contents/Developer
262316

263-
- name: Build iOS app
317+
- name: Build app and run UI tests
264318
working-directory: ios
319+
timeout-minutes: 20
265320
run: |
266-
xcodebuild -project acidwarp-ios.xcodeproj \
267-
-scheme acidwarp \
268-
-configuration Release \
269-
-sdk iphoneos \
270-
-derivedDataPath ./build \
271-
CODE_SIGN_IDENTITY="" \
272-
CODE_SIGNING_REQUIRED=NO \
273-
CODE_SIGNING_ALLOWED=NO
274-
275-
- name: Create iOS app archive
276-
working-directory: ios
321+
chmod +x run-uitests.sh
322+
./run-uitests.sh
323+
324+
- name: Extract screenshots from test results
325+
if: always()
277326
run: |
278-
cd build/Build/Products/Release-iphoneos
279-
zip -r ../../../../acidwarp-ios.zip acidwarp.app
327+
chmod +x extract-test-screenshots.sh
328+
./extract-test-screenshots.sh ios ios/build ios/screenshots
329+
330+
- name: Upload screenshots
331+
if: always()
332+
uses: actions/upload-artifact@v4
333+
with:
334+
name: ios-ui-test-screenshots
335+
path: ios/screenshots/*.png
336+
if-no-files-found: error
337+
338+
339+
340+
# ============================================================================
341+
# WINDOWS UI TEST (GPU RUNNER)
342+
#
343+
# Note: Only runs if all other builds pass, to avoid wasted compute spend
344+
# ============================================================================
345+
windows-ui-test:
346+
name: Windows UI Test
347+
runs-on: windows-x64-2019-gpu
348+
needs: [android, linux, windows, macos, ios]
349+
if: success()
350+
environment: gpu-testing
351+
352+
defaults:
353+
run:
354+
shell: powershell
355+
356+
steps:
357+
- name: Download Windows build artifacts
358+
uses: actions/download-artifact@v4
359+
with:
360+
name: windows-build
361+
362+
- name: Run UI tests
363+
run: .\ui_test.ps1
364+
365+
- name: Upload screenshots
366+
if: always()
367+
uses: actions/upload-artifact@v4
368+
with:
369+
name: windows-ui-test-screenshots
370+
path: screenshots/*.png
371+
if-no-files-found: error
280372

281373

282374

@@ -286,26 +378,28 @@ jobs:
286378
build-summary:
287379
name: Build Summary
288380
runs-on: ubuntu-latest
289-
needs: [android, linux, windows, macos, ios]
381+
needs: [android, linux, windows, macos, ios, windows-ui-test]
290382
if: always()
291383

292384
steps:
293385
- name: Check build results
294386
run: |
295387
echo "Build Summary:"
296388
echo "============================================"
297-
echo "Android: ${{ needs.android.result }}"
298-
echo "Linux: ${{ needs.linux.result }}"
299-
echo "Windows: ${{ needs.windows.result }}"
300-
echo "macOS: ${{ needs.macos.result }}"
301-
echo "iOS: ${{ needs.ios.result }}"
389+
echo "Android: ${{ needs.android.result }}"
390+
echo "Linux: ${{ needs.linux.result }}"
391+
echo "Windows: ${{ needs.windows.result }}"
392+
echo "macOS: ${{ needs.macos.result }}"
393+
echo "iOS: ${{ needs.ios.result }}"
394+
echo "Windows UI Test: ${{ needs.windows-ui-test.result }}"
302395
echo "============================================"
303396
304397
if [[ "${{ needs.android.result }}" == "failure" ]] || \
305398
[[ "${{ needs.linux.result }}" == "failure" ]] || \
306399
[[ "${{ needs.windows.result }}" == "failure" ]] || \
307400
[[ "${{ needs.macos.result }}" == "failure" ]] || \
308-
[[ "${{ needs.ios.result }}" == "failure" ]]; then
401+
[[ "${{ needs.ios.result }}" == "failure" ]] || \
402+
[[ "${{ needs.windows-ui-test.result }}" == "failure" ]]; then
309403
echo "? One or more builds failed"
310404
exit 1
311405
else

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
*.o
2+
*.log
23
./acidwarp
34
acidwarp.exe
45
acidwarp.js

android/app/build.gradle

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@ android {
3030
}
3131
}
3232

33+
testOptions {
34+
animationsDisabled = true
35+
}
36+
3337
sourceSets.main {
3438
jniLibs.srcDir 'libs'
3539
}
@@ -316,3 +320,9 @@ tasks.register('downloadSDL3', DownloadSDL3Task) {
316320
tasks.named('preBuild').configure {
317321
dependsOn 'downloadSDL3'
318322
}
323+
324+
// Configure connected tests to leave APKs installed so we can pull screenshots
325+
tasks.withType(com.android.build.gradle.internal.tasks.DeviceProviderInstrumentTestTask).configureEach {
326+
// Don't uninstall APKs after running tests
327+
uninstallIncompatibleApks = false
328+
}

android/app/src/androidTest/java/com/dermochelys/acidwarp/ActivityUITest.kt

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.dermochelys.acidwarp
22

33
import android.content.Context
4+
import android.view.KeyEvent
45
import androidx.test.core.app.ApplicationProvider
56
import androidx.test.ext.junit.rules.ActivityScenarioRule
67
import androidx.test.ext.junit.runners.AndroidJUnit4
@@ -15,6 +16,7 @@ import org.junit.Before
1516
import org.junit.Rule
1617
import org.junit.Test
1718
import org.junit.runner.RunWith
19+
import java.io.File
1820
import kotlin.time.Duration.Companion.seconds
1921

2022
private const val ERROR_STRING = "SDL Error"
@@ -30,19 +32,33 @@ class ActivityUITest {
3032

3133
private lateinit var context: Context
3234

35+
private lateinit var screenshotDir: File
36+
3337
@Before
3438
fun setUp() {
3539
device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
3640
context = ApplicationProvider.getApplicationContext()
41+
42+
// Create screenshot directory
43+
screenshotDir = File(context.getExternalFilesDir(null), "screenshots")
44+
screenshotDir.mkdirs()
45+
}
46+
47+
private fun takeScreenshot(name: String) {
48+
val screenshotFile = File(screenshotDir, "$name.png")
49+
device.takeScreenshot(screenshotFile)
3750
}
3851

3952
@Test
4053
fun when_appIsLaunched_sdlErrorDialogShouldNotAppear() {
4154
// Wait for the activity to launch
4255
device.wait(Until.hasObject(By.pkg(context.packageName)), 10.seconds.inWholeMilliseconds)
4356

44-
// Wait a moment for any potential dialogs to appear
45-
Thread.sleep(2.seconds.inWholeMilliseconds)
57+
// Wait for app initialization
58+
Thread.sleep(5.seconds.inWholeMilliseconds)
59+
60+
// Capture startup screenshot
61+
takeScreenshot("01-startup")
4662

4763
// Check that the "SDL Error" dialog is not showing
4864
val dllDialog = device.findObject(By.textContains(ERROR_STRING))
@@ -58,5 +74,28 @@ class ActivityUITest {
5874
fail("Found dialog containing '$ERROR_STRING': $dialogText")
5975
}
6076
}
77+
78+
// Test pattern cycling with n key
79+
for (i in 1..5) {
80+
device.pressKeyCode(KeyEvent.KEYCODE_N)
81+
Thread.sleep(4.seconds.inWholeMilliseconds) // Wait for fade-out + fade-in to complete
82+
takeScreenshot("02-pattern-$i")
83+
}
84+
85+
// Test touch input - tap center of screen
86+
val displayWidth = device.displayWidth
87+
val displayHeight = device.displayHeight
88+
device.click(displayWidth / 2, displayHeight / 2)
89+
Thread.sleep(1.seconds.inWholeMilliseconds)
90+
takeScreenshot("03-after-click")
91+
92+
// Test palette change
93+
device.pressKeyCode(KeyEvent.KEYCODE_P)
94+
Thread.sleep(1.seconds.inWholeMilliseconds)
95+
takeScreenshot("04-palette-change")
96+
97+
// Capture final state
98+
Thread.sleep(2.seconds.inWholeMilliseconds)
99+
takeScreenshot("05-final")
61100
}
62101
}

0 commit comments

Comments
 (0)