Enhance screenshot handling
Signed-off-by: tobiasKaminsky <tobias@kaminsky.me>
54
.drone.yml
|
@ -214,3 +214,57 @@ trigger:
|
||||||
event:
|
event:
|
||||||
- push
|
- push
|
||||||
- pull_request
|
- pull_request
|
||||||
|
---
|
||||||
|
kind: pipeline
|
||||||
|
type: docker
|
||||||
|
name: allScreenshots
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: runAllScreenshots
|
||||||
|
image: nextcloudci/android8:android-61
|
||||||
|
privileged: true
|
||||||
|
environment:
|
||||||
|
GIT_USERNAME:
|
||||||
|
from_secret: GIT_USERNAME
|
||||||
|
GIT_TOKEN:
|
||||||
|
from_secret: GIT_TOKEN
|
||||||
|
LOG_USERNAME:
|
||||||
|
from_secret: LOG_USERNAME
|
||||||
|
LOG_PASSWORD:
|
||||||
|
from_secret: LOG_PASSWORD
|
||||||
|
commands:
|
||||||
|
- emulator -avd android -no-snapshot -gpu swiftshader_indirect -no-window -no-audio -skin 500x833 &
|
||||||
|
- sed -i s'#<bool name="is_beta">false</bool>#<bool name="is_beta">true</bool>#'g src/main/res/values/setup.xml
|
||||||
|
- sed -i s'#showOnlyFailingTestsInReports = ciBuild#showOnlyFailingTestsInReports = false#' build.gradle
|
||||||
|
- scripts/wait_for_emulator.sh
|
||||||
|
- scripts/runAllScreenshotCombinations noCI false
|
||||||
|
- scripts/screenshotSummary.sh
|
||||||
|
- name: notify
|
||||||
|
image: drillster/drone-email
|
||||||
|
settings:
|
||||||
|
port: 587
|
||||||
|
from: nextcloud-drone@kaminsky.me
|
||||||
|
recipients_only: true
|
||||||
|
username:
|
||||||
|
from_secret: EMAIL_USERNAME
|
||||||
|
password:
|
||||||
|
from_secret: EMAIL_PASSWORD
|
||||||
|
recipients:
|
||||||
|
from_secret: EMAIL_RECIPIENTS
|
||||||
|
host:
|
||||||
|
from_secret: EMAIL_HOST
|
||||||
|
when:
|
||||||
|
event:
|
||||||
|
- push
|
||||||
|
status:
|
||||||
|
- failure
|
||||||
|
branch:
|
||||||
|
- master
|
||||||
|
- stable-*
|
||||||
|
trigger:
|
||||||
|
branch:
|
||||||
|
- master
|
||||||
|
event:
|
||||||
|
- cron
|
||||||
|
cron:
|
||||||
|
- nightly
|
||||||
|
|
4
.github/workflows/screenShotTest.yml
vendored
|
@ -10,8 +10,8 @@ jobs:
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
scheme: [ Dark, Light ]
|
scheme: [ Light ]
|
||||||
color: [ blue, white, black ]
|
color: [ blue ]
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- name: set up JDK 1.8
|
- name: set up JDK 1.8
|
||||||
|
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 9.5 KiB After Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 23 KiB |
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 35 KiB |
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 5.9 KiB After Width: | Height: | Size: 5.8 KiB |
Before Width: | Height: | Size: 8.2 KiB After Width: | Height: | Size: 8.1 KiB |
Before Width: | Height: | Size: 5.6 KiB After Width: | Height: | Size: 5.6 KiB |
Before Width: | Height: | Size: 6.6 KiB After Width: | Height: | Size: 6.6 KiB |
Before Width: | Height: | Size: 9.3 KiB After Width: | Height: | Size: 9.3 KiB |
85
scripts/generateScreenshotOverview.sh
Executable file
|
@ -0,0 +1,85 @@
|
||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
# Nextcloud Android client application
|
||||||
|
#
|
||||||
|
# @author Tobias Kaminsky
|
||||||
|
# Copyright (C) 2021 Tobias Kaminsky
|
||||||
|
# Copyright (C) 2021 Nextcloud GmbH
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU Affero General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Affero General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Affero General Public License
|
||||||
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
|
||||||
|
error=0
|
||||||
|
total=0
|
||||||
|
|
||||||
|
cp scripts/screenshotCombinations scripts/screenshotCombinations_
|
||||||
|
grep -v "#" scripts/screenshotCombinations_ > scripts/screenshotCombinations
|
||||||
|
rm scripts/screenshotCombinations_
|
||||||
|
|
||||||
|
echo '<!DOCTYPE html>
|
||||||
|
<html lang="de">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8"/>
|
||||||
|
</head>'
|
||||||
|
|
||||||
|
echo "<table>"
|
||||||
|
echo "<tr><td style='width:150px'>Original</td>"
|
||||||
|
while read line; do
|
||||||
|
echo "<td style='width:150px'>$line</td>"
|
||||||
|
done < scripts/screenshotCombinations
|
||||||
|
echo "</tr>"
|
||||||
|
|
||||||
|
#for image in ./build/reports/shot/verification/images/*.png ; do
|
||||||
|
for image in $(/bin/ls -1 ./screenshots/gplay/debug/*.png | grep -v _dark_ | grep -v _light_) ; do
|
||||||
|
cp $image build/screenshotSummary/images/
|
||||||
|
|
||||||
|
echo "<tr style='height:200px'>"
|
||||||
|
echo "<td><a target='_blank' href=\"images/$(basename $image)\"><img width=100px src=\"images/$(basename $image)\"/></a></td>"
|
||||||
|
|
||||||
|
while read line; do
|
||||||
|
echo "<td>"
|
||||||
|
|
||||||
|
mode=$(echo $line | cut -d" " -f1)
|
||||||
|
color=$(echo $line | cut -d" " -f2)
|
||||||
|
total=$((total + 1))
|
||||||
|
|
||||||
|
if [ $mode = "light" -a $color = "blue" ]; then
|
||||||
|
name=$(basename $image)
|
||||||
|
else
|
||||||
|
name=$(basename $image| sed s"/\.png/_${mode}_$color\.png/")
|
||||||
|
fi
|
||||||
|
|
||||||
|
# if image does not exist
|
||||||
|
if [ ! -e ./build/reports/shot/verification/images/$name ]; then
|
||||||
|
echo "<span style='color: red'>✘</span>"
|
||||||
|
error=$((error + 1))
|
||||||
|
elif [ -e ./build/reports/shot/verification/images/diff_$name ]; then
|
||||||
|
# file with "diff_" prefix
|
||||||
|
cp ./build/reports/shot/verification/images/diff_$name build/screenshotSummary/images/
|
||||||
|
echo "<a target='_blank' href=\"images/diff_$name\"><img width=100px src=\"images/diff_$name\"/></a>"
|
||||||
|
error=$((error + 1))
|
||||||
|
else
|
||||||
|
echo "✔"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "</td>"
|
||||||
|
done < scripts/screenshotCombinations
|
||||||
|
|
||||||
|
echo "</tr>"
|
||||||
|
done
|
||||||
|
|
||||||
|
echo "</table>"
|
||||||
|
|
||||||
|
echo "ERROR: $error / $total"
|
||||||
|
echo "</html>"
|
|
@ -16,12 +16,12 @@ fi
|
||||||
classMethod=$3
|
classMethod=$3
|
||||||
|
|
||||||
resultCode=0
|
resultCode=0
|
||||||
while read line
|
grep -v "#" scripts/screenshotCombinations | while read line
|
||||||
do
|
do
|
||||||
darkMode=$(echo "$line" | cut -d" " -f1)
|
darkMode=$(echo "$line" | cut -d" " -f1)
|
||||||
color=$(echo "$line" | cut -d" " -f2)
|
color=$(echo "$line" | cut -d" " -f2)
|
||||||
|
|
||||||
echo "Run $color on $darkMode mode"
|
echo -n "Run $color on $darkMode mode"
|
||||||
|
|
||||||
if [[ $1 = "noCI" ]]; then
|
if [[ $1 = "noCI" ]]; then
|
||||||
./gradlew --console plain gplayDebugExecuteScreenshotTests \
|
./gradlew --console plain gplayDebugExecuteScreenshotTests \
|
||||||
|
@ -32,7 +32,9 @@ do
|
||||||
-Pandroid.testInstrumentationRunnerArguments.DARKMODE="$darkMode" \
|
-Pandroid.testInstrumentationRunnerArguments.DARKMODE="$darkMode" \
|
||||||
$classMethod </dev/null > /dev/null
|
$classMethod </dev/null > /dev/null
|
||||||
if [[ $? -ne 0 ]]; then
|
if [[ $? -ne 0 ]]; then
|
||||||
exit
|
echo " failed!"
|
||||||
|
else
|
||||||
|
echo
|
||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
./gradlew --console plain gplayDebugExecuteScreenshotTests \
|
./gradlew --console plain gplayDebugExecuteScreenshotTests \
|
||||||
|
@ -45,7 +47,7 @@ do
|
||||||
|| resultCode=1 && scripts/uploadReport.sh "$LOG_USERNAME" "$LOG_PASSWORD" "$4" \
|
|| resultCode=1 && scripts/uploadReport.sh "$LOG_USERNAME" "$LOG_PASSWORD" "$4" \
|
||||||
"$1-$darkMode-$color" "Screenshot" "$4" "$GIT_TOKEN"
|
"$1-$darkMode-$color" "Screenshot" "$4" "$GIT_TOKEN"
|
||||||
fi
|
fi
|
||||||
done < scripts/screenshotCombinations
|
done
|
||||||
|
|
||||||
sed -i s'#<bool name="is_beta">true</bool>#<bool name="is_beta">false</bool>#'g src/main/res/values/setup.xml
|
sed -i s'#<bool name="is_beta">true</bool>#<bool name="is_beta">false</bool>#'g src/main/res/values/setup.xml
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,10 @@
|
||||||
light blue
|
light blue
|
||||||
dark blue
|
#dark blue
|
||||||
light white
|
#light white
|
||||||
dark white
|
#dark white
|
||||||
|
#light black
|
||||||
|
#dark black
|
||||||
|
#light red
|
||||||
|
#dark red
|
||||||
|
#light lightgreen
|
||||||
|
dark lightgreen
|
||||||
|
|
30
scripts/screenshotSummary.sh
Executable file
|
@ -0,0 +1,30 @@
|
||||||
|
#!/bin/bash
|
||||||
|
#
|
||||||
|
# Nextcloud Android client application
|
||||||
|
#
|
||||||
|
# @author Tobias Kaminsky
|
||||||
|
# Copyright (C) 2021 Tobias Kaminsky
|
||||||
|
# Copyright (C) 2021 Nextcloud GmbH
|
||||||
|
#
|
||||||
|
# This program is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU Affero General Public License as published by
|
||||||
|
# the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# This program is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Affero General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Affero General Public License
|
||||||
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
#
|
||||||
|
|
||||||
|
mkdir -p build/screenshotSummary/images
|
||||||
|
|
||||||
|
scripts/generateScreenshotOverview.sh > build/screenshotSummary/summary.html
|
||||||
|
error=$?
|
||||||
|
|
||||||
|
scripts/uploadScreenshotSummary.sh $LOG_USERNAME $LOG_PASSWORD
|
||||||
|
|
||||||
|
exit $error
|
17
scripts/uploadScreenshotSummary.sh
Executable file
|
@ -0,0 +1,17 @@
|
||||||
|
#!/bin/bash -x
|
||||||
|
|
||||||
|
#1: LOG_USERNAME
|
||||||
|
#2: LOG_PASSWORD
|
||||||
|
|
||||||
|
DAV_URL=https://nextcloud.kaminsky.me/remote.php/webdav/android-screenshot-summary/
|
||||||
|
PUBLIC_URL=https://www.kaminsky.me/nc-dev/android-screenshot-summary
|
||||||
|
USER=$1
|
||||||
|
PASS=$2
|
||||||
|
|
||||||
|
date=$(date +%F)
|
||||||
|
echo "Uploaded screenshot summary to $PUBLIC_URL/$date/summary.html"
|
||||||
|
|
||||||
|
cd build/screenshotSummary
|
||||||
|
|
||||||
|
find . -type d -exec curl > /dev/null 2>&1 -u $USER:$PASS -X MKCOL $DAV_URL/$date/$(echo {} | sed s#\./##) \;
|
||||||
|
find . -type f -exec curl > /dev/null 2>&1 -u $USER:$PASS -X PUT $DAV_URL/$date/$(echo {} | sed s#\./##) --upload-file {} \;
|
|
@ -27,6 +27,7 @@ import android.Manifest;
|
||||||
import com.owncloud.android.AbstractIT;
|
import com.owncloud.android.AbstractIT;
|
||||||
import com.owncloud.android.R;
|
import com.owncloud.android.R;
|
||||||
import com.owncloud.android.ui.activity.FileDisplayActivity;
|
import com.owncloud.android.ui.activity.FileDisplayActivity;
|
||||||
|
import com.owncloud.android.ui.fragment.OCFileListFragment;
|
||||||
import com.owncloud.android.utils.ScreenshotTest;
|
import com.owncloud.android.utils.ScreenshotTest;
|
||||||
|
|
||||||
import org.junit.Rule;
|
import org.junit.Rule;
|
||||||
|
@ -39,6 +40,7 @@ import androidx.test.rule.GrantPermissionRule;
|
||||||
|
|
||||||
import static androidx.test.espresso.Espresso.onView;
|
import static androidx.test.espresso.Espresso.onView;
|
||||||
import static androidx.test.espresso.matcher.ViewMatchers.withId;
|
import static androidx.test.espresso.matcher.ViewMatchers.withId;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
|
||||||
public class FileDisplayActivityScreenshotIT extends AbstractIT {
|
public class FileDisplayActivityScreenshotIT extends AbstractIT {
|
||||||
@Rule public IntentsTestRule<FileDisplayActivity> activityRule = new IntentsTestRule<>(FileDisplayActivity.class,
|
@Rule public IntentsTestRule<FileDisplayActivity> activityRule = new IntentsTestRule<>(FileDisplayActivity.class,
|
||||||
|
@ -64,14 +66,16 @@ public class FileDisplayActivityScreenshotIT extends AbstractIT {
|
||||||
screenshot(sut);
|
screenshot(sut);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
//@Test
|
||||||
@ScreenshotTest
|
//@ScreenshotTest
|
||||||
public void showMediaThenAllFiles() {
|
public void showMediaThenAllFiles() {
|
||||||
FileDisplayActivity sut = activityRule.launchActivity(null);
|
FileDisplayActivity fileDisplayActivity = activityRule.launchActivity(null);
|
||||||
|
OCFileListFragment sut = fileDisplayActivity.getListOfFilesFragment();
|
||||||
|
assertNotNull(sut);
|
||||||
|
|
||||||
sut.getListOfFilesFragment().setFabEnabled(false);
|
sut.setFabEnabled(false);
|
||||||
sut.getListOfFilesFragment().setEmptyListLoadingMessage();
|
sut.setEmptyListLoadingMessage();
|
||||||
sut.getListOfFilesFragment().setLoading(false);
|
sut.setLoading(false);
|
||||||
|
|
||||||
// open drawer
|
// open drawer
|
||||||
onView(withId(R.id.drawer_layout)).perform(DrawerActions.open());
|
onView(withId(R.id.drawer_layout)).perform(DrawerActions.open());
|
||||||
|
@ -89,11 +93,11 @@ public class FileDisplayActivityScreenshotIT extends AbstractIT {
|
||||||
|
|
||||||
// then compare screenshot
|
// then compare screenshot
|
||||||
shortSleep();
|
shortSleep();
|
||||||
sut.getListOfFilesFragment().setFabEnabled(false);
|
sut.setFabEnabled(false);
|
||||||
sut.getListOfFilesFragment().setEmptyListLoadingMessage();
|
sut.setEmptyListLoadingMessage();
|
||||||
sut.getListOfFilesFragment().setLoading(false);
|
sut.setLoading(false);
|
||||||
shortSleep();
|
shortSleep();
|
||||||
screenshot(sut);
|
screenshot(fileDisplayActivity);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
@ -25,11 +25,9 @@ package com.nextcloud.client.etm
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import androidx.test.espresso.intent.rule.IntentsTestRule
|
import androidx.test.espresso.intent.rule.IntentsTestRule
|
||||||
import androidx.test.internal.runner.junit4.statement.UiThreadStatement
|
import androidx.test.internal.runner.junit4.statement.UiThreadStatement
|
||||||
|
import com.nextcloud.client.preferences.AppPreferencesImpl
|
||||||
import com.owncloud.android.AbstractIT
|
import com.owncloud.android.AbstractIT
|
||||||
import com.owncloud.android.lib.resources.status.OwnCloudVersion
|
|
||||||
import com.owncloud.android.utils.ScreenshotTest
|
import com.owncloud.android.utils.ScreenshotTest
|
||||||
import org.junit.Assume
|
|
||||||
import org.junit.Before
|
|
||||||
import org.junit.Rule
|
import org.junit.Rule
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
|
|
||||||
|
@ -37,16 +35,6 @@ class EtmActivityTest : AbstractIT() {
|
||||||
@get:Rule
|
@get:Rule
|
||||||
var activityRule = IntentsTestRule(EtmActivity::class.java, true, false)
|
var activityRule = IntentsTestRule(EtmActivity::class.java, true, false)
|
||||||
|
|
||||||
@Before
|
|
||||||
fun before() {
|
|
||||||
// tests only on NC 18
|
|
||||||
Assume.assumeTrue(
|
|
||||||
storageManager
|
|
||||||
.getCapability(account.name)
|
|
||||||
.version.compareTo(OwnCloudVersion.nextcloud_18) == 0
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ScreenshotTest
|
@ScreenshotTest
|
||||||
fun overview() {
|
fun overview() {
|
||||||
|
@ -62,7 +50,11 @@ class EtmActivityTest : AbstractIT() {
|
||||||
fun preferences() {
|
fun preferences() {
|
||||||
val sut: EtmActivity = activityRule.launchActivity(null)
|
val sut: EtmActivity = activityRule.launchActivity(null)
|
||||||
|
|
||||||
UiThreadStatement.runOnUiThread { sut.vm.onPageSelected(0) }
|
UiThreadStatement.runOnUiThread {
|
||||||
|
val preferences = AppPreferencesImpl.fromContext(targetContext)
|
||||||
|
preferences.pushToken = "Push token"
|
||||||
|
sut.vm.onPageSelected(0)
|
||||||
|
}
|
||||||
|
|
||||||
screenshot(sut)
|
screenshot(sut)
|
||||||
}
|
}
|
||||||
|
|
|
@ -156,6 +156,10 @@ public abstract class AbstractIT {
|
||||||
colorHex = "#000000";
|
colorHex = "#000000";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case "lightgreen":
|
||||||
|
colorHex = "#aaff00";
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,6 +40,10 @@ class NotificationsActivityIT : AbstractIT() {
|
||||||
fun loading() {
|
fun loading() {
|
||||||
val sut: NotificationsActivity = activityRule.launchActivity(null)
|
val sut: NotificationsActivity = activityRule.launchActivity(null)
|
||||||
|
|
||||||
|
waitForIdleSync()
|
||||||
|
|
||||||
|
sut.runOnUiThread { sut.setLoadingMessageEmpty() }
|
||||||
|
|
||||||
screenshot(sut)
|
screenshot(sut)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -290,7 +290,7 @@ public class RefreshFolderOperation extends RemoteOperation {
|
||||||
} else {
|
} else {
|
||||||
Log_OC.i(TAG, "Got display name: " + result.getResultData());
|
Log_OC.i(TAG, "Got display name: " + result.getResultData());
|
||||||
}
|
}
|
||||||
} catch (AccountUtils.AccountNotFoundException e) {
|
} catch (AccountUtils.AccountNotFoundException | NullPointerException e) {
|
||||||
Log_OC.e(this, "Error updating profile", e);
|
Log_OC.e(this, "Error updating profile", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,7 +61,7 @@ public class RetrieveStatusAsyncTask extends AsyncTask<Void, Void, Status> {
|
||||||
} else {
|
} else {
|
||||||
return new com.owncloud.android.lib.resources.users.Status(StatusType.OFFLINE, "", "", -1);
|
return new com.owncloud.android.lib.resources.users.Status(StatusType.OFFLINE, "", "", -1);
|
||||||
}
|
}
|
||||||
} catch (ClientFactory.CreationException e) {
|
} catch (ClientFactory.CreationException | NullPointerException e) {
|
||||||
return new com.owncloud.android.lib.resources.users.Status(StatusType.OFFLINE, "", "", -1);
|
return new com.owncloud.android.lib.resources.users.Status(StatusType.OFFLINE, "", "", -1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|