Skip to content
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

fix: ci and e2e test #383

Merged
merged 30 commits into from
Nov 4, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
93ffe6b
fix: Display proper error content in e2e test
ShootingKing-AM Oct 26, 2022
1859f06
Update nodejs.yml
ShootingKing-AM Oct 26, 2022
cb34fc0
fix: check errors after taking screenshot
ShootingKing-AM Oct 26, 2022
14aa47b
fix: Display proper error content in e2e test (#6)
ShootingKing-AM Oct 26, 2022
ab87014
add timeline initial load screenshot
ShootingKing-AM Oct 27, 2022
ca58f24
increase loading time for timeline view test
ShootingKing-AM Oct 27, 2022
baada3a
Implement an indefinite wait for timeline view test
ShootingKing-AM Oct 27, 2022
2e14613
Restore general 20 seconds timeout for other tests
ShootingKing-AM Oct 27, 2022
58617ca
Merge branch 'master' into fix-ci-error-log
ShootingKing-AM Oct 27, 2022
1692dad
fix: Selector element missing after initial lookup
ShootingKing-AM Oct 27, 2022
4a748f6
rewrite waiting functions to get Selection elements instantly
ShootingKing-AM Oct 27, 2022
dbfcd3b
Added HTTP request logger and console errors logger
ShootingKing-AM Oct 27, 2022
1a4616d
remove implemented indefinite wait and attach loggers to all fixtures
ShootingKing-AM Oct 27, 2022
e97efc1
fix fakedate ENDDATE
ShootingKing-AM Oct 27, 2022
740e7c5
Update screenshot.test.js
ShootingKing-AM Oct 27, 2022
81cb00e
Update screenshot.test.js
ShootingKing-AM Oct 27, 2022
fc0768d
Bump activitywatch version
ShootingKing-AM Oct 27, 2022
56b9827
Update nodejs.yml
ShootingKing-AM Oct 27, 2022
cfad6b6
try to test with master
ShootingKing-AM Oct 27, 2022
4ddbdca
Update nodejs.yml
ShootingKing-AM Oct 27, 2022
d6481ad
Print server logs to github actions console
ShootingKing-AM Oct 27, 2022
99081bc
Update nodejs.yml
ShootingKing-AM Oct 27, 2022
dc878d5
test with Logs
ShootingKing-AM Oct 27, 2022
87ceacc
Update nodejs.yml
ShootingKing-AM Oct 27, 2022
edc6337
Update nodejs.yml
ShootingKing-AM Oct 27, 2022
667bc34
implement a refresh after 10s
ShootingKing-AM Oct 27, 2022
70d103c
implement refresh time and max times
ShootingKing-AM Oct 27, 2022
9c63eee
cleanup workflow file
ShootingKing-AM Oct 28, 2022
1dc6749
Update nodejs.yml
ShootingKing-AM Oct 28, 2022
512f690
add master branch of aw-server-rust to ci
ShootingKing-AM Nov 3, 2022
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
41 changes: 33 additions & 8 deletions .github/workflows/nodejs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,12 @@ jobs:
node-version: [16]
python-version: ['3.9']
aw-server: ["aw-server", "aw-server-rust"]
aw-version: ["v0.12.0"]
#include:
#- node-version: '16'
# python-version: '3.9'
# aw-server: "aw-server-rust"
# aw-version: "master"
aw-version: ["v0.12.1"]
include:
- node-version: '16'
python-version: '3.9'
aw-server: "aw-server-rust"
aw-version: "master"

steps:
- uses: actions/checkout@v2
Expand Down Expand Up @@ -103,15 +103,16 @@ jobs:
if: ${{ matrix.aw-server == 'aw-server-rust' && matrix.aw-version == 'master' }}
run: |
chmod +x ./aw-server-rust/debug/aw-server
./aw-server-rust/debug/aw-server --testing &
LOG_LEVEL=debug ./aw-server-rust/debug/aw-server --testing &

- name: Insert fake data into aw-server
run: |
pip install click git+https://github.com/ActivityWatch/aw-client.git
wget --no-verbose -O fakedata.py https://raw.githubusercontent.com/ActivityWatch/aw-fakedata/master/aw_fakedata.py
GITDATE=$(git show -s --format=%ci HEAD | sed -r 's/ .+//g')
STARTDATE=$(date --date="${GITDATE} -30 day" +%Y-%m-%d)
python3 fakedata.py --since $STARTDATE --until $GITDATE
ENDDATE=$(date --date="${GITDATE} +1 day" +%Y-%m-%d)
python3 fakedata.py --since $STARTDATE --until $ENDDATE
ErikBjare marked this conversation as resolved.
Show resolved Hide resolved

- name: Install
run: npm ci
Expand All @@ -124,19 +125,43 @@ jobs:
npm run serve &
sleep 3 # give a few seconds
- name: Run e2e tests with testcafe
id: e2e
uses: DevExpress/testcafe-action@latest
with:
# NOTE: --skip-js-errors should be removed when things work properly
args: "--skip-js-errors chrome test/e2e/"
- name: Move screenshots to subdir
# Run this step even if e2e tests flag failure
if: ${{ success() || steps.e2e.conclusion == 'failure'}}
env:
aw_server: ${{ matrix.aw-server }}
aw_version: ${{ matrix.aw-version }}
run: |
mkdir -p screenshots/dist/$aw_server/$aw_version
mv screenshots/*.png screenshots/dist/$aw_server/$aw_version
- name: Upload screenshots
if: ${{ success() || steps.e2e.conclusion == 'failure'}}
ErikBjare marked this conversation as resolved.
Show resolved Hide resolved
uses: actions/upload-artifact@v2-preview
with:
name: screenshots
path: screenshots/dist/*
- name: Print server logs to console
if: ${{ always() }}
shell: bash
run:
for file in ~/.cache/activitywatch/log/*/*.log; do echo $file; cat $file; echo; done
- name: Move logs to subdir
# Run this step even if e2e tests flag failure
if: ${{ always() }}
env:
aw_server: ${{ matrix.aw-server }}
aw_version: ${{ matrix.aw-version }}
run: |
mkdir -p logs/dist/$aw_server/$aw_version
mv ~/.cache/activitywatch/log/*/*.log logs/dist/$aw_server/$aw_version
- name: Upload logs
if: ${{ always() }}
uses: actions/upload-artifact@v2-preview
with:
name: logs
path: logs/dist/*
ErikBjare marked this conversation as resolved.
Show resolved Hide resolved
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ test:
npm test

test-e2e:
npx testcafe firefox test/e2e/ -s takeOnFails=true
npx testcafe chrome test/e2e/ -s takeOnFails=true
ShootingKing-AM marked this conversation as resolved.
Show resolved Hide resolved

typing-coverage:
npx typescript-coverage-report
Expand Down
101 changes: 71 additions & 30 deletions test/e2e/screenshot.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,21 @@
/* eslint jest/expect-expect: "off" */

import { Selector } from 'testcafe';
import { RequestLogger } from 'testcafe';

const MAX_REFRESH = 2; // the max number of times to refresh if "Loading..." dosent go away
const REFRESH_TIMEPERIOD = 5000; //ms - refresh page after waiting for this amount of ms for "Loading..." to dissapear
const MAX_WAIT_TIME = 20000; //ms - max time to wait for "Loading..." to dissapear after all refreshes

const baseURL = 'http://127.0.0.1:27180';
const HTTPLogger = RequestLogger(/^(?:(?!\.js|\.css|\.png|\.woff2).)+$/, {
logRequestHeaders: true,
logResponseHeaders: true,
logRequestBody: true,
logResponseBody: true,
stringifyRequestBody: true,
stringifyResponseBody: true,
});

async function hide_devonly(t) {
// Hide all devonly-elements
Expand All @@ -17,50 +30,60 @@ async function hide_devonly(t) {
async function waitForLoading(t) {
// Waits for all "Loading..." texts to disappear from page.
// If it takes longer than 10s, it will fail.
let $loading;
let matches = 1;
let $loading,
refresh_count = 0;

console.log('Waiting for loading to disappear...');
const start = new Date();
let start = new Date();
do {
$loading = Selector('.aw-loading, text', { timeout: 500 }).withText(/Loading[.]{3}/g);
$loading = await Selector('.aw-loading, text', { timeout: 500 }).withText(/Loading[.]{3}/g)();

// Useful for debugging:
matches = await $loading.count;
if (matches > 0) {
console.log(`Found ${matches} loading element with contents`); //: ${await $loading.innerText}`);
if ($loading) {
console.log(`Found loading element with contents - "${$loading.textContent}"`);

if (new Date() - start > REFRESH_TIMEPERIOD && refresh_count < MAX_REFRESH) {
console.log('Refreshing page....');
await t.eval(() => location.reload(true));
refresh_count++;
start = new Date();
}

// If taking >20s, throw an error
if (new Date() - start > 20000) {
if (new Date() - start > MAX_WAIT_TIME && refresh_count >= MAX_REFRESH) {
console.log(await t.getBrowserConsoleMessages());
console.log(JSON.stringify(HTTPLogger.requests, null, '\t'));
throw new Error('Timeout while waiting for loading to disappear');
}
await t.wait(500);
}
} while (matches >= 1);
} while ($loading);

await t.wait(500); // wait an extra 500ms, just in case a visualization is still rendering
console.log('Loading is gone!');
}

async function checkNoError(t) {
const $error = Selector('div').withText(/[Ee]rror/g);
const $error = Selector('div.alert').withText(/[Ee]rror/g);
try {
await t.expect(await $error.count).eql(0);
} catch (e) {
console.log('Errors found: ' + $error);
console.log('Errors found: ' + (await $error.textContent));
throw e;
}
}

const logJsErrorCode = `
window.addEventListener('error', function (e) {
console.error(e.message);
});`;

fixture(`Home view`).page(baseURL);

// Log JS errors even if --skip-js-errors is given
// From: https://stackoverflow.com/a/59856422/965332
test.clientScripts({
content: `
window.addEventListener('error', function (e) {
console.error(e.message);
});`,
content: logJsErrorCode,
})(`Skip error but log it`, async t => {
console.log(await t.getBrowserConsoleMessages());
});
Expand All @@ -80,29 +103,36 @@ test('Screenshot the home view', async t => {
});
});

fixture(`Activity view`).page(`${baseURL}/#/activity/fakedata`);
fixture(`Activity view`).page(`${baseURL}/#/activity/fakedata`).requestHooks(HTTPLogger);

test('Screenshot the activity view', async t => {
test.clientScripts({
content: logJsErrorCode,
})('Screenshot the activity view', async t => {
await hide_devonly(t);
await waitForLoading(t);
await checkNoError(t);
await t.takeScreenshot({
path: 'activity.png',
fullPage: true,
});
await checkNoError(t);
ErikBjare marked this conversation as resolved.
Show resolved Hide resolved

// TODO: resize to mobile size and take another screenshot
});

fixture(`Timeline view`).page(`${baseURL}/#/timeline`);
fixture(`Timeline view`).page(`${baseURL}/#/timeline`).requestHooks(HTTPLogger);

const durationSelect = Selector('select#duration');
const durationOption = durationSelect.find('option');

test('Screenshot the timeline view', async t => {
test.clientScripts({
content: logJsErrorCode,
})('Screenshot the timeline view', async t => {
await hide_devonly(t);
await t.takeScreenshot({
path: 'timeline-initial.png',
fullPage: true,
});
await waitForLoading(t);
await checkNoError(t);
await t
.click(durationSelect)
.click(durationOption.withText('12h'))
Expand All @@ -113,39 +143,50 @@ test('Screenshot the timeline view', async t => {
path: 'timeline.png',
fullPage: true,
});
await checkNoError(t);

// Debugging
// console.log(await t.getBrowserConsoleMessages());
// console.log(JSON.stringify(HTTPLogger.requests, null, '\t'));
});

fixture(`Buckets view`).page(`${baseURL}/#/buckets/`);
fixture(`Buckets view`).page(`${baseURL}/#/buckets/`).requestHooks(HTTPLogger);

test('Screenshot the buckets view', async t => {
test.clientScripts({
content: logJsErrorCode,
})('Screenshot the buckets view', async t => {
await hide_devonly(t);
await t.wait(1000);
await checkNoError(t);
await t.takeScreenshot({
path: 'buckets.png',
fullPage: true,
});
await checkNoError(t);
});

fixture(`Setting view`).page(`${baseURL}/#/settings/`);
fixture(`Setting view`).page(`${baseURL}/#/settings/`).requestHooks(HTTPLogger);

test('Screenshot the settings view', async t => {
test.clientScripts({
content: logJsErrorCode,
})('Screenshot the settings view', async t => {
await hide_devonly(t);
await checkNoError(t);
await t.takeScreenshot({
path: 'settings.png',
fullPage: true,
});
await checkNoError(t);
});

fixture(`Stopwatch view`).page(`${baseURL}/#/stopwatch/`);
fixture(`Stopwatch view`).page(`${baseURL}/#/stopwatch/`).requestHooks(HTTPLogger);

test('Screenshot the stopwatch view', async t => {
test.clientScripts({
content: logJsErrorCode,
})('Screenshot the stopwatch view', async t => {
await hide_devonly(t);
await waitForLoading(t);
await checkNoError(t);
await t.takeScreenshot({
path: 'stopwatch.png',
fullPage: true,
});
await checkNoError(t);
});